diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml
index 1625fa7c8a..449aaec2c8 100644
--- a/.github/workflows/presubmit.yml
+++ b/.github/workflows/presubmit.yml
@@ -56,11 +56,21 @@ jobs:
env:
GCM_SECRET: ${{ secrets.GCM_SECRET }}
run: make test-script-gcm
+ e2e-testruns:
+ runs-on: ubuntu-latest
+ outputs:
+ testrun: ${{ steps.set-testruns.outputs.testrun }}
+ steps:
+ - uses: actions/checkout@v3
+ - id: set-testruns
+ run: echo "testrun=$(go test ./e2e/... -list=. | grep -E 'Test*' | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
e2e-test:
runs-on: ubuntu-latest
+ needs: [e2e-testruns]
+ strategy:
+ matrix:
+ testrun: ${{fromJson(needs.e2e-testruns.outputs.testrun)}}
steps:
- uses: actions/checkout@v3
- name: Run e2e
- run: make e2e
- env:
- GO_ARGS: "-timeout=15m -parallel=2"
+ run: TEST_RUN=${{matrix.testrun}} make e2e
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 174b66f33b..4ebae26c51 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ E2E_DOCKER_ARGS += --env KIND_PERSIST=1
endif
REGISTRY_NAME=kind-registry
REGISTRY_PORT=5001
-KIND_PARALLEL?=5
+KIND_PARALLEL?=3
# For now assume the docker daemon is mounted through a unix socket.
# TODO(pintohutch): will this work if using a remote docker over tcp?
diff --git a/e2e/authorization_test.go b/e2e/authorization_test.go
index c0f274ecb6..b852f4c827 100644
--- a/e2e/authorization_test.go
+++ b/e2e/authorization_test.go
@@ -16,309 +16,318 @@ package e2e
import (
"context"
- "crypto/tls"
- "crypto/x509"
+ "errors"
"fmt"
"strings"
"testing"
- "github.com/GoogleCloudPlatform/prometheus-engine/e2e/kubeutil"
- "github.com/GoogleCloudPlatform/prometheus-engine/e2e/operatorutil"
- "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator"
monitoringv1 "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator/apis/monitoring/v1"
- appsv1 "k8s.io/api/apps/v1"
+ "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator/generated/clientset/versioned"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
+ "k8s.io/client-go/kubernetes"
)
-func isPodMonitoringTargetCertificateError(message string) error {
- err := tls.CertificateVerificationError{
- Err: x509.UnknownAuthorityError{},
- }
- expected := err.Error()
- if !strings.HasSuffix(message, expected) {
- return fmt.Errorf("expected %q", expected)
- }
- return nil
-}
-
-func isPodMonitoringTargetUnauthorizedError(message string) error {
- const expected = "server returned HTTP status 401 Unauthorized"
- if message != expected {
- return fmt.Errorf("expected %q", expected)
- }
- return nil
-}
-
-func defaultEndpoint(endpoint *monitoringv1.ScrapeEndpoint) {
- endpoint.Port = intstr.FromString(operatorutil.SyntheticAppPortName)
- endpoint.Interval = "5s"
-}
-
-// TODO(TheSpiritXIII): This helper is temporary until we add secret management.
-func setupAuthTestMissingAuth(ctx context.Context, t *OperatorContext, appName string, args []string, podMonitoringNamePrefix string, endpointNoAuth monitoringv1.ScrapeEndpoint, expectedFn func(string) error) *appsv1.Deployment {
- defaultEndpoint(&endpointNoAuth)
-
- deployment, err := operatorutil.SyntheticAppDeploy(ctx, t.Client(), t.userNamespace, appName, args)
+func TestTLSPodMonitoring(t *testing.T) {
+ ctx := context.Background()
+ kubeClient, opClient, err := newKubeClients()
if err != nil {
- t.Fatal(err)
- }
- if err := kubeutil.WaitForDeploymentReady(ctx, t.Client(), t.userNamespace, appName); err != nil {
- kubeutil.DeploymentDebug(t.T, ctx, t.RestConfig(), t.Client(), t.userNamespace, appName)
- t.Fatalf("failed to start app: %s", err)
+ t.Fatalf("error instantiating clients. err: %s", err)
}
- t.Run("podmon-missing-config", t.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
+ t.Run("collector-deployed", testCollectorDeployed(ctx, t, kubeClient))
+ t.Run("enable-target-status", testEnableTargetStatus(ctx, t, opClient))
+ t.Run("patch-example-app-args", testPatchExampleAppArgs(ctx, t, kubeClient, []string{"--tls-create-self-signed=true"}))
- pm := &monitoringv1.PodMonitoring{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("pod%s-missing-config", podMonitoringNamePrefix),
- Namespace: t.userNamespace,
+ pm := &monitoringv1.PodMonitoring{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tls-ready",
+ Namespace: "default",
+ },
+ Spec: monitoringv1.PodMonitoringSpec{
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app": "go-synthetic",
+ },
},
- Spec: monitoringv1.PodMonitoringSpec{
- Selector: metav1.LabelSelector{
- MatchLabels: deployment.Spec.Template.Labels,
+ Endpoints: []monitoringv1.ScrapeEndpoint{
+ {
+ Scheme: "https",
+ Port: intstr.FromString("web"),
+ Interval: "5s",
+ HTTPClientConfig: monitoringv1.HTTPClientConfig{
+ TLS: &monitoringv1.TLS{
+ InsecureSkipVerify: true,
+ },
+ },
},
- Endpoints: []monitoringv1.ScrapeEndpoint{endpointNoAuth},
},
- }
- if err := t.Client().Create(ctx, pm); err != nil {
- t.Fatalf("create collector PodMonitoring: %s", err)
- }
-
- if err := operatorutil.WaitForPodMonitoringReady(ctx, t.Client(), t.namespace, pm, true); err != nil {
- kubeutil.DaemonSetDebug(t.T, ctx, t.RestConfig(), t.Client(), t.namespace, operator.NameCollector)
- t.Fatalf("PodMonitoring not ready: %s", err)
- }
-
- if err := operatorutil.WaitForPodMonitoringFailure(ctx, t.Client(), pm, expectedFn); err != nil {
- kubeutil.DaemonSetDebug(t.T, ctx, t.RestConfig(), t.Client(), t.namespace, operator.NameCollector)
- t.Fatalf("scrape endpoint expected failure: %s", err)
- }
- }))
-
- t.Run("clusterpodmon-missing-config", t.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
+ },
+ }
+ t.Run("tls-podmonitoring-ready", testEnsurePodMonitoringReady(ctx, t, opClient, pm))
- pm := &monitoringv1.ClusterPodMonitoring{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("%s-c%s-failure", t.namespace, podMonitoringNamePrefix),
+ pmFail := &monitoringv1.PodMonitoring{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tls-fail",
+ Namespace: "default",
+ },
+ Spec: monitoringv1.PodMonitoringSpec{
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app": "go-synthetic",
+ },
},
- Spec: monitoringv1.ClusterPodMonitoringSpec{
- Selector: metav1.LabelSelector{
- MatchLabels: deployment.Spec.Template.Labels,
+ Endpoints: []monitoringv1.ScrapeEndpoint{
+ {
+ Scheme: "https",
+ Port: intstr.FromString("web"),
+ Interval: "5s",
},
- Endpoints: []monitoringv1.ScrapeEndpoint{endpointNoAuth},
},
- }
- if err := t.Client().Create(ctx, pm); err != nil {
- t.Fatalf("create collector PodMonitoring: %s", err)
- }
-
- if err := operatorutil.WaitForPodMonitoringReady(ctx, t.Client(), t.namespace, pm, true); err != nil {
- kubeutil.DaemonSetDebug(t.T, ctx, t.RestConfig(), t.Client(), t.namespace, operator.NameCollector)
- t.Fatalf("collector not ready: %s", err)
- }
-
- if err := operatorutil.WaitForPodMonitoringFailure(ctx, t.Client(), pm, expectedFn); err != nil {
- kubeutil.DaemonSetDebug(t.T, ctx, t.RestConfig(), t.Client(), t.namespace, operator.NameCollector)
- t.Fatalf("scrape endpoint expected failure: %s", err)
- }
- }))
-
- return deployment
+ },
+ }
+ errMsg := "x509: certificate signed by unknown authority"
+ t.Run("tls-podmonitoring-failure", testEnsurePodMonitoringFailure(ctx, t, opClient, pmFail, errMsg))
}
-// setupAuthTest sets up tests for PodMonitoring and ClusterPodMonitoring for when
-// authentication configurations are present and when they are not present.
-func setupAuthTest(ctx context.Context, t *OperatorContext, appName string, args []string, podMonitoringNamePrefix string, endpointNoAuth, endpointAuth monitoringv1.ScrapeEndpoint, expectedFn func(string) error) {
- defaultEndpoint(&endpointAuth)
- deployment := setupAuthTestMissingAuth(ctx, t, appName, args, podMonitoringNamePrefix, endpointNoAuth, expectedFn)
+func TestTLSClusterPodMonitoring(t *testing.T) {
+ ctx := context.Background()
+ kubeClient, opClient, err := newKubeClients()
+ if err != nil {
+ t.Fatalf("error instantiating clients. err: %s", err)
+ }
- t.Run("podmon-success", t.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
+ t.Run("collector-deployed", testCollectorDeployed(ctx, t, kubeClient))
+ t.Run("enable-target-status", testEnableTargetStatus(ctx, t, opClient))
+ t.Run("patch-example-app-args", testPatchExampleAppArgs(ctx, t, kubeClient, []string{"--tls-create-self-signed=true"}))
- pm := &monitoringv1.PodMonitoring{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("pod%s-success", podMonitoringNamePrefix),
- Namespace: t.userNamespace,
+ cpm := &monitoringv1.ClusterPodMonitoring{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tls-ready",
+ Namespace: "default",
+ },
+ Spec: monitoringv1.ClusterPodMonitoringSpec{
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app": "go-synthetic",
+ },
},
- Spec: monitoringv1.PodMonitoringSpec{
- Selector: metav1.LabelSelector{
- MatchLabels: deployment.Spec.Template.Labels,
+ Endpoints: []monitoringv1.ScrapeEndpoint{
+ {
+ Scheme: "https",
+ Port: intstr.FromString("web"),
+ Interval: "5s",
+ HTTPClientConfig: monitoringv1.HTTPClientConfig{
+ TLS: &monitoringv1.TLS{
+ InsecureSkipVerify: true,
+ },
+ },
},
- Endpoints: []monitoringv1.ScrapeEndpoint{endpointAuth},
},
- }
- if err := t.Client().Create(ctx, pm); err != nil {
- t.Fatalf("create collector: %s", err)
- }
-
- if err := operatorutil.WaitForPodMonitoringReady(ctx, t.Client(), t.namespace, pm, true); err != nil {
- kubeutil.DaemonSetDebug(t.T, ctx, t.RestConfig(), t.Client(), t.namespace, operator.NameCollector)
- t.Errorf("collector not ready: %s", err)
- }
-
- if err := operatorutil.WaitForPodMonitoringSuccess(ctx, t.Client(), pm); err != nil {
- kubeutil.DaemonSetDebug(t.T, ctx, t.RestConfig(), t.Client(), t.namespace, operator.NameCollector)
- t.Fatalf("scrape endpoint expected success: %s", err)
- }
- }))
-
- t.Run("clusterpodmon-success", t.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
+ },
+ }
+ t.Run("tls-clusterpodmonitoring-ready", testEnsureClusterPodMonitoringReady(ctx, t, opClient, cpm))
- pm := &monitoringv1.ClusterPodMonitoring{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("c%s-success", podMonitoringNamePrefix),
+ cpmFail := &monitoringv1.ClusterPodMonitoring{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "tls-fail",
+ Namespace: "default",
+ },
+ Spec: monitoringv1.ClusterPodMonitoringSpec{
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app": "go-synthetic",
+ },
},
- Spec: monitoringv1.ClusterPodMonitoringSpec{
- Selector: metav1.LabelSelector{
- MatchLabels: deployment.Spec.Template.Labels,
+ Endpoints: []monitoringv1.ScrapeEndpoint{
+ {
+ Scheme: "https",
+ Port: intstr.FromString("web"),
+ Interval: "5s",
},
- Endpoints: []monitoringv1.ScrapeEndpoint{endpointAuth},
},
- }
- if err := t.Client().Create(ctx, pm); err != nil {
- t.Fatalf("create collector: %s", err)
- }
-
- if err := operatorutil.WaitForPodMonitoringReady(ctx, t.Client(), t.namespace, pm, true); err != nil {
- kubeutil.DaemonSetDebug(t.T, ctx, t.RestConfig(), t.Client(), t.namespace, operator.NameCollector)
- t.Errorf("collector not ready: %s", err)
- }
-
- if err := operatorutil.WaitForPodMonitoringSuccess(ctx, t.Client(), pm); err != nil {
- kubeutil.DaemonSetDebug(t.T, ctx, t.RestConfig(), t.Client(), t.namespace, operator.NameCollector)
- t.Fatalf("scrape endpoint expected success: %s", err)
- }
- }))
+ },
+ }
+ errMsg := "x509: certificate signed by unknown authority"
+ t.Run("tls-clusterpodmonitoring-failure", testEnsureClusterPodMonitoringFailure(ctx, t, opClient, cpmFail, errMsg))
}
-func TestTLS(t *testing.T) {
- t.Parallel()
- tctx := newOperatorContext(t)
+func TestBasicAuthPodMonitoring(t *testing.T) {
ctx := context.Background()
+ kubeClient, opClient, err := newKubeClients()
+ if err != nil {
+ t.Fatalf("error instantiating clients. err: %s", err)
+ }
+
+ t.Run("collector-deployed", testCollectorDeployed(ctx, t, kubeClient))
+ t.Run("enable-target-status", testEnableTargetStatus(ctx, t, opClient))
+ t.Run("patch-example-app-args", testPatchExampleAppArgs(ctx, t, kubeClient, []string{"--basic-auth-username=user"}))
- tctx.createOperatorConfigFrom(ctx, monitoringv1.OperatorConfig{
- Features: monitoringv1.OperatorFeatures{
- TargetStatus: monitoringv1.TargetStatusSpec{
- Enabled: true,
+ pm := &monitoringv1.PodMonitoring{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "basic-auth-ready",
+ Namespace: "default",
+ },
+ Spec: monitoringv1.PodMonitoringSpec{
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app": "go-synthetic",
+ },
+ },
+ Endpoints: []monitoringv1.ScrapeEndpoint{
+ {
+ Port: intstr.FromString("web"),
+ Interval: "5s",
+ HTTPClientConfig: monitoringv1.HTTPClientConfig{
+ BasicAuth: &monitoringv1.BasicAuth{
+ Username: "user",
+ },
+ },
+ },
},
},
- })
+ }
+ t.Run("basic-auth-podmonitoring-ready", testEnsurePodMonitoringReady(ctx, t, opClient, pm))
- const appName = "tls-insecure"
- setupAuthTest(ctx, tctx, appName, []string{
- "--tls-create-self-signed=true",
- }, "mon-tls-insecure",
- monitoringv1.ScrapeEndpoint{
- Scheme: "https",
- }, monitoringv1.ScrapeEndpoint{
- Scheme: "https",
- HTTPClientConfig: monitoringv1.HTTPClientConfig{
- TLS: &monitoringv1.TLS{
- InsecureSkipVerify: true,
+ pmFail := &monitoringv1.PodMonitoring{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "basic-auth-fail",
+ Namespace: "default",
+ },
+ Spec: monitoringv1.PodMonitoringSpec{
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app": "go-synthetic",
+ },
+ },
+ Endpoints: []monitoringv1.ScrapeEndpoint{
+ {
+ Port: intstr.FromString("web"),
+ Interval: "5s",
},
},
- }, isPodMonitoringTargetCertificateError)
+ },
+ }
+ errMsg := "server returned HTTP status 401 Unauthorized"
+ t.Run("basic-auth-podmonitoring-failure", testEnsurePodMonitoringFailure(ctx, t, opClient, pmFail, errMsg))
}
-func TestBasicAuth(t *testing.T) {
- t.Parallel()
- tctx := newOperatorContext(t)
+func TestBasicAuthClusterPodMonitoring(t *testing.T) {
ctx := context.Background()
+ kubeClient, opClient, err := newKubeClients()
+ if err != nil {
+ t.Fatalf("error instantiating clients. err: %s", err)
+ }
- tctx.createOperatorConfigFrom(ctx, monitoringv1.OperatorConfig{
- Features: monitoringv1.OperatorFeatures{
- TargetStatus: monitoringv1.TargetStatusSpec{
- Enabled: true,
+ t.Run("collector-deployed", testCollectorDeployed(ctx, t, kubeClient))
+ t.Run("enable-target-status", testEnableTargetStatus(ctx, t, opClient))
+ t.Run("patch-example-app-args", testPatchExampleAppArgs(ctx, t, kubeClient, []string{"--basic-auth-username=user"}))
+
+ cpm := &monitoringv1.ClusterPodMonitoring{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "basic-auth-ready",
+ Namespace: "default",
+ },
+ Spec: monitoringv1.ClusterPodMonitoringSpec{
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app": "go-synthetic",
+ },
+ },
+ Endpoints: []monitoringv1.ScrapeEndpoint{
+ {
+ Port: intstr.FromString("web"),
+ Interval: "5s",
+ HTTPClientConfig: monitoringv1.HTTPClientConfig{
+ BasicAuth: &monitoringv1.BasicAuth{
+ Username: "user",
+ },
+ },
+ },
},
},
- })
+ }
+ t.Run("basic-auth-clusterpodmonitoring-ready", testEnsureClusterPodMonitoringReady(ctx, t, opClient, cpm))
- t.Run("no-password", tctx.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
- const appName = "basic-auth-no-password"
- const appUsername = "gmp-user-basic-auth-no-password"
- setupAuthTest(ctx, t, appName, []string{
- fmt.Sprintf("--basic-auth-username=%s", appUsername),
- }, "mon-basic-auth-no-password", monitoringv1.ScrapeEndpoint{}, monitoringv1.ScrapeEndpoint{
- HTTPClientConfig: monitoringv1.HTTPClientConfig{
- BasicAuth: &monitoringv1.BasicAuth{
- Username: appUsername,
+ cpmFail := &monitoringv1.ClusterPodMonitoring{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "basic-auth-fail",
+ Namespace: "default",
+ },
+ Spec: monitoringv1.ClusterPodMonitoringSpec{
+ Selector: metav1.LabelSelector{
+ MatchLabels: map[string]string{
+ "app": "go-synthetic",
},
},
- }, isPodMonitoringTargetUnauthorizedError)
- }))
-
- t.Run("no-username", tctx.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
- const appName = "basic-auth-no-username"
- const appPassword = "secret-no-username"
- setupAuthTestMissingAuth(ctx, t, appName, []string{
- fmt.Sprintf("--basic-auth-password=%s", appPassword),
- }, "mon-basic-auth-no-username", monitoringv1.ScrapeEndpoint{}, isPodMonitoringTargetUnauthorizedError)
- }))
-
- t.Run("full", tctx.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
- const appName = "basic-auth-full"
- const appUsername = "gmp-user-basic-auth-full"
- const appPassword = "secret-full"
- setupAuthTestMissingAuth(ctx, t, appName, []string{
- fmt.Sprintf("--basic-auth-username=%s", appUsername),
- fmt.Sprintf("--basic-auth-password=%s", appPassword),
- }, "mon-basic-auth-full", monitoringv1.ScrapeEndpoint{}, isPodMonitoringTargetUnauthorizedError)
- }))
-}
-
-func TestAuthorization(t *testing.T) {
- t.Parallel()
- tctx := newOperatorContext(t)
- ctx := context.Background()
-
- tctx.createOperatorConfigFrom(ctx, monitoringv1.OperatorConfig{
- Features: monitoringv1.OperatorFeatures{
- TargetStatus: monitoringv1.TargetStatusSpec{
- Enabled: true,
+ Endpoints: []monitoringv1.ScrapeEndpoint{
+ {
+ Port: intstr.FromString("web"),
+ Interval: "5s",
+ },
},
},
- })
-
- t.Run("no-credentials", tctx.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
- const appName = "auth-no-credentials"
- // TODO(TheSpiritXIII): Add authorization with bearer but no credentials.
- setupAuthTestMissingAuth(ctx, t, appName, []string{
- "--auth-scheme=Bearer",
- }, "mon-auth-no-credentials", monitoringv1.ScrapeEndpoint{}, isPodMonitoringTargetUnauthorizedError)
- }))
+ }
+ errMsg := "server returned HTTP status 401 Unauthorized"
+ t.Run("basic-auth-clusterpodmonitoring-failure", testEnsureClusterPodMonitoringFailure(ctx, t, opClient, cpmFail, errMsg))
}
-func TestOAuth2(t *testing.T) {
- t.Parallel()
- tctx := newOperatorContext(t)
- ctx := context.Background()
+func testPatchExampleAppArgs(ctx context.Context, t *testing.T, kubeClient kubernetes.Interface, args []string) func(*testing.T) {
+ return func(t *testing.T) {
+ deploy, err := kubeClient.AppsV1().Deployments("default").Get(ctx, "go-synthetic", metav1.GetOptions{})
+ if err != nil {
+ t.Errorf("create deployment: %s", err)
+ }
- tctx.createOperatorConfigFrom(ctx, monitoringv1.OperatorConfig{
- Features: monitoringv1.OperatorFeatures{
- TargetStatus: monitoringv1.TargetStatusSpec{
- Enabled: true,
- },
- },
- })
+ cargs := deploy.Spec.Template.Spec.Containers[0].Args
+ newArgs := append(cargs, args...)
+ deploy.Spec.Template.Spec.Containers[0].Args = newArgs
+ _, err = kubeClient.AppsV1().Deployments("default").Update(ctx, deploy, metav1.UpdateOptions{})
+ if err != nil {
+ t.Errorf("update deployment: %s", err)
+ }
+ }
+}
- t.Run("no-client-secret", tctx.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
- const appName = "oauth2-no-client-secret"
- const clientID = "gmp-user-client-id-no-client-secret"
- const clientScope = "read"
+func isPodMonitoringScrapeEndpointFailure(status *monitoringv1.ScrapeEndpointStatus, errMsg string) error {
+ if status.UnhealthyTargets == 0 {
+ return errors.New("expected no healthy targets")
+ }
+ if status.CollectorsFraction == "0" {
+ return fmt.Errorf("expected collectors fraction to be 0 but found: %s", status.CollectorsFraction)
+ }
+ if len(status.SampleGroups) == 0 {
+ return errors.New("missing sample groups")
+ }
+ for i, group := range status.SampleGroups {
+ if len(group.SampleTargets) == 0 {
+ return fmt.Errorf("missing sample targets for group %d", i)
+ }
+ for _, target := range group.SampleTargets {
+ if target.Health == "up" {
+ return fmt.Errorf("healthy target %q at group %d", target.Health, i)
+ }
+ if target.LastError == nil {
+ return fmt.Errorf("missing error for target at group %d", i)
+ }
+ if !strings.Contains(*target.LastError, errMsg) {
+ return fmt.Errorf("expected error message %q at group %d: got %s", errMsg, i, *target.LastError)
+ }
+ }
+ }
+ return nil
+}
+
+func testEnsurePodMonitoringFailure(ctx context.Context, t *testing.T, opClient versioned.Interface, pm *monitoringv1.PodMonitoring, errMsg string) func(*testing.T) {
+ return testEnsurePodMonitoringStatus(ctx, t, opClient, pm,
+ func(status *monitoringv1.ScrapeEndpointStatus) error {
+ return isPodMonitoringScrapeEndpointFailure(status, errMsg)
+ })
+}
- setupAuthTestMissingAuth(ctx, t, appName, []string{
- fmt.Sprintf("--oauth2-client-id=%s", clientID),
- fmt.Sprintf("--oauth2-scopes=%s", clientScope),
- }, "mon-authorization-no-credentials", monitoringv1.ScrapeEndpoint{}, isPodMonitoringTargetUnauthorizedError)
- }))
+func testEnsureClusterPodMonitoringFailure(ctx context.Context, t *testing.T, opClient versioned.Interface, cpm *monitoringv1.ClusterPodMonitoring, errMsg string) func(*testing.T) {
+ return testEnsureClusterPodMonitoringStatus(ctx, t, opClient, cpm,
+ func(status *monitoringv1.ScrapeEndpointStatus) error {
+ return isPodMonitoringScrapeEndpointFailure(status, errMsg)
+ })
}
diff --git a/e2e/googleutil.go b/e2e/googleutil.go
deleted file mode 100644
index 1c2f814999..0000000000
--- a/e2e/googleutil.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package e2e
-
-import (
- "fmt"
- "strings"
-
- "k8s.io/client-go/tools/clientcmd"
-)
-
-type ClusterMeta struct {
- ProjectID string
- Cluster string
- Location string
-}
-
-// ExtractGKEClusterMeta extracts the current GKE cluster meta-data using the local Kubernetes config.
-func ExtractGKEClusterMeta() (ClusterMeta, error) {
- config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
- clientcmd.NewDefaultClientConfigLoadingRules(),
- &clientcmd.ConfigOverrides{
- CurrentContext: "",
- }).RawConfig()
- if err != nil {
- return ClusterMeta{}, err
- }
- prefix := "gke_"
- if !strings.HasPrefix(config.CurrentContext, prefix) {
- return ClusterMeta{}, fmt.Errorf("context is not GKE context: %s", config.CurrentContext)
- }
- // Google Cloud Projects, GKE cluster and locations don't allow underscores.
- context := strings.SplitN(config.CurrentContext[len(prefix):], "_", 3)
- return ClusterMeta{
- ProjectID: context[0],
- Cluster: context[2],
- Location: context[1],
- }, nil
-}
diff --git a/e2e/kubeutil/client.go b/e2e/kubeutil/client.go
deleted file mode 100644
index 5e7305fec5..0000000000
--- a/e2e/kubeutil/client.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package kubeutil
-
-import (
- "context"
-
- "k8s.io/apimachinery/pkg/api/meta"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
-)
-
-type DelegatingClient interface {
- client.Client
- Base() client.Client
-}
-
-// delegatingWriteSubResourceClient delegates all mutating functions to a writer client.
-type delegatingWriteSubResourceClient struct {
- base client.SubResourceClient
- writer client.SubResourceWriter
-}
-
-func (c *delegatingWriteSubResourceClient) Get(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceGetOption) error {
- return c.base.Get(ctx, obj, subResource, opts...)
-}
-
-func (c *delegatingWriteSubResourceClient) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error {
- return c.writer.Create(ctx, obj, subResource, opts...)
-}
-
-func (c *delegatingWriteSubResourceClient) Update(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
- return c.writer.Update(ctx, obj, opts...)
-}
-
-func (c *delegatingWriteSubResourceClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
- return c.writer.Patch(ctx, obj, patch, opts...)
-}
-
-// WriterClient comprises of all mutating functions in client.Client.
-type WriterClient interface {
- client.Writer
- client.StatusClient
- SubResource(subResource string) client.SubResourceWriter
-}
-
-// delegatingWriteClient delegates all mutating functions to a writer client.
-type delegatingWriteClient struct {
- base client.Client
- writer WriterClient
-}
-
-func (c *delegatingWriteClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
- return c.base.Get(ctx, key, obj, opts...)
-}
-
-func (c *delegatingWriteClient) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
- return c.base.List(ctx, list, opts...)
-}
-
-func (c *delegatingWriteClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
- return c.writer.Create(ctx, obj, opts...)
-}
-
-func (c *delegatingWriteClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
- return c.writer.Delete(ctx, obj, opts...)
-}
-
-func (c *delegatingWriteClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- return c.writer.Update(ctx, obj, opts...)
-}
-
-func (c *delegatingWriteClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
- return c.writer.Patch(ctx, obj, patch, opts...)
-}
-
-func (c *delegatingWriteClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
- return c.writer.DeleteAllOf(ctx, obj, opts...)
-}
-
-func (c *delegatingWriteClient) SubResource(subResource string) client.SubResourceClient {
- return &delegatingWriteSubResourceClient{
- base: c.base.SubResource(subResource),
- writer: c.writer.SubResource(subResource),
- }
-}
-
-func (c *delegatingWriteClient) Status() client.SubResourceWriter {
- return c.writer.Status()
-}
-
-func (c *delegatingWriteClient) Scheme() *runtime.Scheme {
- return c.base.Scheme()
-}
-
-func (c *delegatingWriteClient) RESTMapper() meta.RESTMapper {
- return c.base.RESTMapper()
-}
-
-func (c *delegatingWriteClient) Base() client.Client {
- return c.base
-}
-
-func newDelegatingWriteClient(c client.Client, w WriterClient) DelegatingClient {
- return &delegatingWriteClient{
- base: c,
- writer: w,
- }
-}
-
-func (c *delegatingWriteClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
- return c.base.GroupVersionKindFor(obj)
-}
-
-func (c *delegatingWriteClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
- return c.base.IsObjectNamespaced(obj)
-}
-
-// labelWriterClient adds common labels to all objects mutated by this client.
-type labelWriterClient struct {
- base client.Client
- labels map[string]string
-}
-
-func (c *labelWriterClient) setLabels(obj client.Object) {
- labels := obj.GetLabels()
- if labels == nil {
- labels = map[string]string{}
- }
- for k, v := range c.labels {
- labels[k] = v
- }
- obj.SetLabels(labels)
-}
-
-func (c *labelWriterClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
- c.setLabels(obj)
- return c.base.Create(ctx, obj, opts...)
-}
-
-func (c *labelWriterClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
- return c.base.Delete(ctx, obj, opts...)
-}
-
-func (c *labelWriterClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- c.setLabels(obj)
- return c.base.Update(ctx, obj, opts...)
-}
-
-func (c *labelWriterClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
- // Ensure the patch doesn't remove the labels by applying the new patch.
- latestObj := obj.DeepCopyObject().(client.Object)
- if err := c.base.Get(ctx, client.ObjectKeyFromObject(obj), latestObj); err != nil {
- return err
- }
- fakeClient := fake.
- NewClientBuilder().
- WithRESTMapper(c.base.RESTMapper()).
- WithScheme(c.base.Scheme()).
- WithObjects(latestObj).
- Build()
- if err := fakeClient.Patch(ctx, obj, patch, opts...); err != nil {
- return err
- }
- return c.Update(ctx, obj)
-}
-
-func (c *labelWriterClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
- return c.base.DeleteAllOf(ctx, obj, opts...)
-}
-
-func (c *labelWriterClient) SubResource(subResource string) client.SubResourceWriter {
- return c.base.SubResource(subResource)
-}
-
-func (c *labelWriterClient) Status() client.SubResourceWriter {
- return c.base.Status()
-}
-
-func NewLabelWriterClient(c client.Client, labels map[string]string) DelegatingClient {
- return newDelegatingWriteClient(c, &labelWriterClient{
- base: c,
- labels: labels,
- })
-}
diff --git a/e2e/kubeutil/container.go b/e2e/kubeutil/container.go
deleted file mode 100644
index b9cd8f8565..0000000000
--- a/e2e/kubeutil/container.go
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package kubeutil
-
-import (
- "context"
- "errors"
- "fmt"
- "strings"
- "testing"
-
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func containerStateString(state *corev1.ContainerState) string {
- if state.Waiting != nil {
- return fmt.Sprintf("waiting due to %s", state.Waiting.Reason)
- }
- if state.Terminated != nil {
- return fmt.Sprintf("terminated due to %s", state.Terminated.Reason)
- }
- return "running"
-}
-
-func containerPods(ctx context.Context, kubeClient client.Client, o client.Object) ([]corev1.Pod, error) {
- switch o := o.(type) {
- case *appsv1.Deployment:
- return DeploymentPods(ctx, kubeClient, o)
- case *appsv1.DaemonSet:
- return DaemonSetPods(ctx, kubeClient, o)
- default:
- return nil, errors.New("invalid object type")
- }
-}
-
-func containerDebug(t testing.TB, ctx context.Context, restConfig *rest.Config, kubeClient client.Client, gvk schema.GroupVersionKind, o client.Object, typeName string) {
- namespace := o.GetNamespace()
- name := o.GetName()
- t.Logf("%s %s/%s events:", typeName, namespace, name)
- events, err := Events(ctx, kubeClient, gvk, namespace, name)
- if err != nil {
- t.Errorf("unable to get %s %s/%s events: %s", typeName, namespace, name, err)
- } else {
- t.Log(strings.Join(events, "\n"))
- }
-
- if err := kubeClient.Get(ctx, client.ObjectKeyFromObject(o), o); err != nil {
- t.Fatalf("unable to get deployment %s/%s: %s", namespace, name, err)
- }
-
- // Best effort to find a problematic pod container.
- pods, err := containerPods(ctx, kubeClient, o)
- if err != nil {
- t.Errorf("unable to get container pods")
- }
- if len(pods) == 0 {
- t.Log("no pods found for this deployment")
- return
- }
-
- showPodLogs := func(pod *corev1.Pod, container string) {
- t.Logf("sample pod %s/%s container %s logs:", pod.Namespace, pod.Name, container)
- logs, err := PodLogs(ctx, restConfig, pod.Namespace, pod.Name, container)
- if err != nil {
- t.Errorf("unable to get pod %s/%s container %s logs: %s", pod.Namespace, pod.Name, container, err)
- } else {
- t.Log(logs)
- }
- }
-
- for _, pod := range pods {
- found := false
- for _, status := range pod.Status.ContainerStatuses {
- // The pod is crash-looping.
- if status.RestartCount > 1 {
- found = true
- showPodLogs(&pod, status.Name)
- }
- }
- // Not perfect, but hopefully we found an issue.
- if found {
- return
- }
- }
-
- // Worse case, let's just show the first one.
- t.Log("found no crash-looping pods -- showing logs of first pod")
- if len(pods) > 0 {
- pod := pods[0]
- for _, status := range pod.Status.ContainerStatuses {
- showPodLogs(&pod, status.Name)
- }
- }
-}
diff --git a/e2e/kubeutil/daemonset.go b/e2e/kubeutil/daemonset.go
deleted file mode 100644
index d4651c696e..0000000000
--- a/e2e/kubeutil/daemonset.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package kubeutil
-
-import (
- "context"
- "errors"
- "fmt"
- "testing"
- "time"
-
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func isDaemonSetReady(daemonSet *appsv1.DaemonSet) error {
- ready := daemonSet.Status.NumberReady
- if ready == 0 {
- return errors.New("no pods ready")
- }
-
- unavailable := daemonSet.Status.NumberUnavailable
- if unavailable != 0 {
- return fmt.Errorf("%d pods unavailable", unavailable)
- }
- return nil
-}
-
-func WaitForDaemonSetReady(ctx context.Context, kubeClient client.Client, namespace, name string) error {
- daemonSet := &appsv1.DaemonSet{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- },
- }
- return waitForResourceReady(ctx, kubeClient, daemonSet, 4*time.Minute, isDaemonSetReady)
-}
-
-func DaemonSetPods(ctx context.Context, kubeClient client.Client, daemonSet *appsv1.DaemonSet) ([]corev1.Pod, error) {
- return selectorPods(ctx, kubeClient, daemonSet.Spec.Selector)
-}
-
-// DaemonSetDebug prints the DaemonSetDebug events and pod logs to the test logger.
-func DaemonSetDebug(t testing.TB, ctx context.Context, restConfig *rest.Config, kubeClient client.Client, namespace, name string) {
- daemonSet := appsv1.DaemonSet{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: namespace,
- Name: name,
- },
- }
- containerDebug(t, ctx, restConfig, kubeClient, schema.GroupVersionKind{
- Version: "v1",
- Kind: "DaemonSet",
- }, &daemonSet, "daemonset")
-}
diff --git a/e2e/kubeutil/deployment.go b/e2e/kubeutil/deployment.go
deleted file mode 100644
index 82495e6985..0000000000
--- a/e2e/kubeutil/deployment.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package kubeutil
-
-import (
- "context"
- "errors"
- "fmt"
- "testing"
- "time"
-
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func isDeploymentReady(deployment *appsv1.Deployment) error {
- // Set to default replicas value.
- expected := int32(1)
- if deployment.Spec.Replicas != nil {
- expected = *deployment.Spec.Replicas
- }
- if deployment.Status.ReadyReplicas != expected {
- return errors.New("replicas unavailable")
- }
- return nil
-}
-
-func WaitForDeploymentReady(ctx context.Context, kubeClient client.Client, namespace, name string) error {
- deployment := &appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- },
- }
- return waitForResourceReady(ctx, kubeClient, deployment, 2*time.Minute, isDeploymentReady)
-}
-
-func DeploymentContainer(deployment *appsv1.Deployment, name string) (*corev1.Container, error) {
- for i := range deployment.Spec.Template.Spec.Containers {
- container := &deployment.Spec.Template.Spec.Containers[i]
- if container.Name == name {
- return container, nil
- }
- }
- return nil, fmt.Errorf("unable to find container %q", name)
-}
-
-func DeploymentPods(ctx context.Context, kubeClient client.Client, deployment *appsv1.Deployment) ([]corev1.Pod, error) {
- return selectorPods(ctx, kubeClient, deployment.Spec.Selector)
-}
-
-func DeploymentDebug(t *testing.T, ctx context.Context, restConfig *rest.Config, kubeClient client.Client, namespace, name string) {
- deployment := appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: namespace,
- Name: name,
- },
- }
- containerDebug(t, ctx, restConfig, kubeClient, schema.GroupVersionKind{
- Version: "v1",
- Kind: "Deployment",
- }, &deployment, "deployment")
-}
diff --git a/e2e/kubeutil/logs.go b/e2e/kubeutil/logs.go
deleted file mode 100644
index 58c11a702f..0000000000
--- a/e2e/kubeutil/logs.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package kubeutil
-
-import (
- "context"
- "io"
- "strings"
-
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/fields"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/kubernetes"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// PodLogs returns the logs of the pod with the given name.
-func PodLogs(ctx context.Context, restConfig *rest.Config, namespace, name, container string) (string, error) {
- clientset, err := kubernetes.NewForConfig(restConfig)
- if err != nil {
- return "", err
- }
- req := clientset.CoreV1().Pods(namespace).GetLogs(name, &corev1.PodLogOptions{
- Container: container,
- })
- podLogs, err := req.Stream(ctx)
- if err != nil {
- return "", err
- }
- builder := strings.Builder{}
- if _, err := io.Copy(&builder, podLogs); err != nil {
- return "", err
- }
- return builder.String(), nil
-}
-
-// Events returns the events of the given resource.
-func Events(ctx context.Context, kubeClient client.Client, gvk schema.GroupVersionKind, namespace, name string) ([]string, error) {
- var msgs []string
- events := corev1.EventList{}
- apiVersion, kind := gvk.ToAPIVersionAndKind()
- if err := kubeClient.List(ctx, &events, client.InNamespace(namespace), client.MatchingFieldsSelector{
- Selector: fields.SelectorFromSet(fields.Set(map[string]string{
- "involvedObject.apiVersion": apiVersion,
- "involvedObject.kind": kind,
- "involvedObject.name": name,
- })),
- }); err != nil {
- return nil, err
- }
- for _, ev := range events.Items {
- msgs = append(msgs, ev.Message)
- }
- return msgs, nil
-}
diff --git a/e2e/kubeutil/network.go b/e2e/kubeutil/network.go
deleted file mode 100644
index 912f42d1b3..0000000000
--- a/e2e/kubeutil/network.go
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package kubeutil
-
-import (
- "context"
- "fmt"
- "io"
- "net"
- "net/http"
- "strings"
- "testing"
- "time"
-
- "k8s.io/client-go/rest"
- "k8s.io/client-go/tools/portforward"
- "k8s.io/client-go/transport/spdy"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// wrappedConn simply wraps a net.Conn with an additional close function.
-type wrappedConn struct {
- conn net.Conn
- closeFn func()
-}
-
-func (c *wrappedConn) Read(b []byte) (n int, err error) {
- return c.conn.Read(b)
-}
-
-func (c *wrappedConn) Write(b []byte) (n int, err error) {
- return c.conn.Write(b)
-}
-
-func (c *wrappedConn) Close() error {
- err := c.conn.Close()
- c.closeFn()
- return err
-}
-
-func (c *wrappedConn) LocalAddr() net.Addr {
- return c.conn.LocalAddr()
-}
-
-func (c *wrappedConn) RemoteAddr() net.Addr {
- return c.conn.RemoteAddr()
-}
-
-func (c *wrappedConn) SetDeadline(t time.Time) error {
- return c.conn.SetDeadline(t)
-}
-
-func (c *wrappedConn) SetReadDeadline(t time.Time) error {
- return c.conn.SetReadDeadline(t)
-}
-
-func (c *wrappedConn) SetWriteDeadline(t time.Time) error {
- return c.conn.SetWriteDeadline(t)
-}
-
-type writerFn func(p []byte) (n int, err error)
-
-func (w *writerFn) Write(p []byte) (n int, err error) {
- return (*w)(p)
-}
-
-func writerFromFn(fn func(p []byte) (n int, err error)) io.Writer {
- w := writerFn(fn)
- return &w
-}
-
-// PortForwardClient returns a client that ports-forward all Kubernetes-local HTTP requests to the host.
-func PortForwardClient(t testing.TB, restConfig *rest.Config, kubeClient client.Client) (*http.Client, error) {
- restClient, err := rest.RESTClientFor(restConfig)
- if err != nil {
- return nil, fmt.Errorf("unable to create REST client: %w", err)
- }
-
- return &http.Client{
- Transport: &http.Transport{
- DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
- if network != "tcp" {
- return nil, fmt.Errorf("network %q unsupported", network)
- }
- addr, err := net.ResolveTCPAddr(network, address)
- if err != nil {
- return nil, fmt.Errorf("unable to resolve TCP addr: %w", err)
- }
-
- pod, container, err := PodByAddr(ctx, kubeClient, addr)
- if err != nil {
- return nil, fmt.Errorf("unable to get pod from IP %s: %w", addr.IP, err)
- }
- if err := WaitForPodContainerReady(ctx, t, restConfig, kubeClient, pod, container); err != nil {
- return nil, fmt.Errorf("failed waiting for pod from IP %s: %w", addr.IP, err)
- }
- resourceURL := restClient.
- Post().
- Resource("pods").
- Namespace(pod.GetNamespace()).
- Name(pod.GetName()).
- SubResource("portforward").
- URL()
-
- transport, upgrader, err := spdy.RoundTripperFor(restConfig)
- if err != nil {
- return nil, err
- }
- client := &http.Client{
- Transport: transport,
- }
-
- stopCh := make(chan struct{})
- readyCh := make(chan struct{})
- errCh := make(chan error)
- forwardDialer := spdy.NewDialer(upgrader, client, http.MethodPost, resourceURL)
- forwarder, err := portforward.NewOnAddresses(
- forwardDialer,
- // Specify IPv4 address explicitly, since GitHub Actions does not support IPv6.
- []string{"127.0.0.1"},
- // The leading colon indicates that a random port is chosen.
- []string{fmt.Sprintf(":%d", addr.Port)},
- stopCh,
- readyCh,
- writerFromFn(func(p []byte) (n int, err error) {
- t.Log(strings.TrimRight(string(p), " \n"))
- return len(p), nil
- }),
- writerFromFn(func(p []byte) (n int, err error) {
- t.Error(strings.TrimRight(string(p), " \n"))
- return len(p), nil
- }),
- )
- if err != nil {
- return nil, err
- }
-
- go func() {
- if err := forwarder.ForwardPorts(); err != nil {
- errCh <- err
- }
- close(errCh)
- }()
-
- close := func() {
- // readyCh is closed by the port-forwarder.
- close(stopCh)
- }
-
- select {
- case <-readyCh:
- ports, err := forwarder.GetPorts()
- if err != nil {
- return nil, err
- }
- if len(ports) != 1 {
- return nil, fmt.Errorf("expected 1 port but found %d", len(ports))
- }
- port := ports[0]
-
- // Pass in tcp4 to ensure we always get IPv4 and never IPv6.
- var dialer net.Dialer
- conn, err := dialer.DialContext(ctx, "tcp4", fmt.Sprintf("127.0.0.1:%d", port.Local))
- if err != nil {
- return nil, err
- }
- return &wrappedConn{
- conn: conn,
- closeFn: close,
- }, nil
- case <-stopCh:
- close()
- return nil, fmt.Errorf("port forwarding stopped unexpectedly")
- case err := <-errCh:
- close()
- return nil, fmt.Errorf("port forwarding failed: %w", err)
- }
- },
- },
- }, nil
-}
diff --git a/e2e/kubeutil/parse.go b/e2e/kubeutil/parse.go
deleted file mode 100644
index 15a835166d..0000000000
--- a/e2e/kubeutil/parse.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package kubeutil
-
-import (
- "errors"
- "fmt"
- "os"
- "strings"
-
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/serializer"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func ParseResourceYAML(scheme *runtime.Scheme, b []byte) (client.Object, error) {
- codec := serializer.NewCodecFactory(scheme)
- // Ignore returned schema. It's redundant since it's already encoded in obj.
- obj, _, err := codec.UniversalDeserializer().Decode(b, nil, nil)
- if err != nil {
- return nil, err
- }
- clientObj, ok := obj.(client.Object)
- if !ok {
- return nil, fmt.Errorf("unable to convert resource into client object: %s", obj.GetObjectKind().GroupVersionKind().String())
- }
- return clientObj, err
-}
-
-func ResourcesFromFile(scheme *runtime.Scheme, filepath string) ([]client.Object, error) {
- fileBytes, err := os.ReadFile(filepath)
- if err != nil {
- return nil, fmt.Errorf("read YAML at path %q: %w", filepath, err)
- }
-
- var objs []client.Object
- var errs []error
- for i, doc := range strings.Split(string(fileBytes), "---") {
- obj, err := ParseResourceYAML(scheme, []byte(doc))
- if err != nil {
- errs = append(errs, fmt.Errorf("decode resource yaml %d: %w", i, err))
- continue
- }
- objs = append(objs, obj)
- }
-
- if err := errors.Join(errs...); err != nil {
- return nil, fmt.Errorf("at path %q: %w", filepath, err)
- }
-
- return objs, nil
-}
-
-func ResourceFromFile(scheme *runtime.Scheme, filepath string) (client.Object, error) {
- objs, err := ResourcesFromFile(scheme, filepath)
- if err != nil {
- return nil, err
- }
- if len(objs) != 1 {
- return nil, fmt.Errorf("expected 1 resource but found %d at path %q", len(objs), filepath)
- }
- return objs[0], nil
-}
diff --git a/e2e/kubeutil/pod.go b/e2e/kubeutil/pod.go
deleted file mode 100644
index 0be73b5fdf..0000000000
--- a/e2e/kubeutil/pod.go
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package kubeutil
-
-import (
- "context"
- "errors"
- "fmt"
- "net"
- "testing"
- "time"
-
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/fields"
- "k8s.io/apimachinery/pkg/labels"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func IsPodContainerReady(ctx context.Context, restConfig *rest.Config, pod *corev1.Pod, container string) error {
- for _, status := range pod.Status.ContainerStatuses {
- if status.Name == container {
- if !status.Ready {
- key := client.ObjectKeyFromObject(pod)
- return fmt.Errorf("pod %s container %s not ready: %s", key, status.Name, containerStateString(&status.State))
- }
- return nil
- }
- }
- key := client.ObjectKeyFromObject(pod)
- return fmt.Errorf("no container named %s found in pod %s", container, key)
-}
-
-func WaitForPodContainerReady(ctx context.Context, t testing.TB, restConfig *rest.Config, kubeClient client.Client, pod *corev1.Pod, container string) error {
- return waitForResourceReady(ctx, kubeClient, pod, 1*time.Minute, func(pod *corev1.Pod) error {
- return IsPodContainerReady(ctx, restConfig, pod, container)
- })
-}
-
-func IsPodReady(ctx context.Context, restConfig *rest.Config, pod *corev1.Pod) error {
- var errs []error
- for _, status := range pod.Status.ContainerStatuses {
- if !status.Ready {
- key := client.ObjectKeyFromObject(pod)
- errs = append(errs, fmt.Errorf("pod %s container %s not ready: %s", key, status.Name, containerStateString(&status.State)))
- }
- }
- return errors.Join(errs...)
-}
-
-func WaitForPodReady(ctx context.Context, t *testing.T, restConfig *rest.Config, kubeClient client.Client, pod *corev1.Pod) error {
- return waitForResourceReady(ctx, kubeClient, pod, 30*time.Second, func(pod *corev1.Pod) error {
- return IsPodReady(ctx, restConfig, pod)
- })
-}
-
-func PodByIP(ctx context.Context, kubeClient client.Client, ip net.IP) (*corev1.Pod, error) {
- var pods corev1.PodList
- if err := kubeClient.List(ctx, &pods, &client.ListOptions{
- FieldSelector: fields.OneTermEqualSelector("status.podIP", ip.String()),
- }); err != nil {
- return nil, err
- }
- if len(pods.Items) != 1 {
- return nil, fmt.Errorf("expected 1 pod with IP %s, got %d", ip.String(), len(pods.Items))
- }
- return &pods.Items[0], nil
-}
-
-func PodByAddr(ctx context.Context, kubeClient client.Client, addr *net.TCPAddr) (*corev1.Pod, string, error) {
- pod, err := PodByIP(ctx, kubeClient, addr.IP)
- if err != nil {
- return nil, "", err
- }
- for _, container := range pod.Spec.Containers {
- for _, port := range container.Ports {
- if int(port.ContainerPort) == addr.Port {
- return pod, container.Name, nil
- }
- }
- }
- key := client.ObjectKeyFromObject(pod)
- return nil, "", fmt.Errorf("unable to find port %d in pod %s", addr.Port, key)
-}
-
-func selectorPods(ctx context.Context, kubeClient client.Client, selector *metav1.LabelSelector) ([]corev1.Pod, error) {
- var podList corev1.PodList
- requirements, err := labels.ParseToRequirements(metav1.FormatLabelSelector(selector))
- if err != nil {
- return nil, err
- }
- if err := kubeClient.List(ctx, &podList, &client.MatchingLabelsSelector{
- Selector: labels.NewSelector().Add(requirements...),
- }); err != nil {
- return nil, err
- }
- return podList.Items, nil
-}
diff --git a/e2e/kubeutil/resource.go b/e2e/kubeutil/resource.go
deleted file mode 100644
index dda678181c..0000000000
--- a/e2e/kubeutil/resource.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package kubeutil
-
-import (
- "context"
- "errors"
- "fmt"
- "time"
-
- "k8s.io/apimachinery/pkg/util/wait"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
-)
-
-func waitForResourceReady[T client.Object](ctx context.Context, kubeClient client.Client, o T, duration time.Duration, readyFn func(o T) error) error {
- var err error
- if waitErr := wait.PollUntilContextTimeout(ctx, 3*time.Second, duration, true, func(ctx context.Context) (bool, error) {
- if err = kubeClient.Get(ctx, client.ObjectKeyFromObject(o), o); err != nil {
- return false, nil
- }
- if err = readyFn(o); err != nil {
- return false, nil
- }
- return true, nil
- }); waitErr != nil {
- if errors.Is(waitErr, context.DeadlineExceeded) && err != nil {
- waitErr = err
- }
- gvk, err := apiutil.GVKForObject(o, kubeClient.Scheme())
- if err != nil {
- return fmt.Errorf("unable to get GVK: %w", err)
- }
- return fmt.Errorf("resource %s %s/%s not ready: %w", gvk.String(), o.GetNamespace(), o.GetName(), waitErr)
- }
- return nil
-}
diff --git a/e2e/operator_context_test.go b/e2e/operator_context_test.go
deleted file mode 100644
index 8453e60a6c..0000000000
--- a/e2e/operator_context_test.go
+++ /dev/null
@@ -1,673 +0,0 @@
-// Copyright 2022 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package e2e contains tests that validate the behavior of gmp-operator against a cluster.
-// To make tests simple and fast, the test suite runs the operator internally. The CRDs
-// are expected to be installed out of band (along with the operator deployment itself in
-// a real world setup).
-package e2e
-
-import (
- "context"
- "errors"
- "flag"
- "fmt"
- "net/http"
- "os"
- "os/signal"
- "strings"
- "syscall"
- "testing"
- "time"
-
- "github.com/prometheus/client_golang/prometheus"
- "go.uber.org/zap/zapcore"
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- rbacv1 "k8s.io/api/rbac/v1"
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/api/meta"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/labels"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/apimachinery/pkg/selection"
- "k8s.io/client-go/discovery"
- "k8s.io/client-go/kubernetes/scheme"
- "k8s.io/client-go/rest"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
- "sigs.k8s.io/controller-runtime/pkg/log/zap"
- "sigs.k8s.io/controller-runtime/pkg/webhook"
-
- "github.com/GoogleCloudPlatform/prometheus-engine/e2e/kubeutil"
- "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator"
- monitoringv1 "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator/apis/monitoring/v1"
-)
-
-const (
- collectorManifest = "../cmd/operator/deploy/operator/10-collector.yaml"
- ruleEvalManifest = "../cmd/operator/deploy/operator/11-rule-evaluator.yaml"
- alertmanagerManifest = "../cmd/operator/deploy/operator/12-alertmanager.yaml"
-
- testLabel = "monitoring.googleapis.com/prometheus-test"
-)
-
-var (
- startTime = time.Now().UTC()
- globalLogger = zap.New(zap.Level(zapcore.DebugLevel))
-
- kubeconfig *rest.Config
- gcpServiceAccount string
- portForward bool
- leakResources bool
- cleanup bool
-)
-
-func init() {
- ctrl.SetLogger(globalLogger)
-
- // Allow tests to run on random webhook ports to allow parallelism.
- webhook.DefaultPort = 0
-}
-
-func newClient() (client.Client, error) {
- scheme, err := operator.NewScheme()
- if err != nil {
- return nil, fmt.Errorf("operator schema: %w", err)
- }
-
- return client.New(kubeconfig, client.Options{
- Scheme: scheme,
- })
-}
-
-func setRESTConfigDefaults(restConfig *rest.Config) error {
- // https://github.com/kubernetes/client-go/issues/657
- // https://github.com/kubernetes/client-go/issues/1159
- // https://github.com/kubernetes/kubectl/blob/6fb6697c77304b7aaf43a520d30cb17563c69886/pkg/cmd/util/kubectl_match_version.go#L115
- defaultGroupVersion := &schema.GroupVersion{Group: "", Version: "v1"}
- if restConfig.GroupVersion == nil {
- restConfig.GroupVersion = defaultGroupVersion
- }
- if restConfig.APIPath == "" {
- restConfig.APIPath = "/api"
- }
- if restConfig.NegotiatedSerializer == nil {
- restConfig.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
- }
- return rest.SetKubernetesDefaults(restConfig)
-}
-
-// TestMain injects custom flags and adds extra signal handling to ensure testing
-// namespaces are cleaned after tests were executed.
-func OldTestMain(m *testing.M) {
- cleanupOnly := false
- flag.StringVar(&projectID, "project-id", "", "The GCP project to write metrics to.")
- flag.StringVar(&cluster, "cluster", "", "The name of the Kubernetes cluster that's tested against.")
- flag.StringVar(&location, "location", "", "The location of the Kubernetes cluster that's tested against.")
- flag.BoolVar(&skipGCM, "skip-gcm", false, "Skip validating GCM ingested points.")
- flag.StringVar(&gcpServiceAccount, "gcp-service-account", "", "Path to GCP service account file for usage by deployed containers.")
- flag.BoolVar(&portForward, "port-forward", true, "Whether to port-forward Kubernetes HTTP requests.")
- flag.BoolVar(&leakResources, "leak-resources", true, "If set, prevents deleting resources. Useful for debugging.")
- flag.BoolVar(&cleanup, "cleanup-resources", true, "If set, cleans resources before running tests.")
- flag.BoolVar(&cleanupOnly, "cleanup-resources-only", cleanupOnly, "If set, cleans resources and then exits.")
-
- flag.Parse()
-
- if projectID == "" && cluster == "" && location == "" {
- clusterMeta, err := ExtractGKEClusterMeta()
- if err != nil {
- fmt.Fprintln(os.Stdout, "Unable to load GKE Cluster meta:", err)
- } else {
- projectID = clusterMeta.ProjectID
- cluster = clusterMeta.Cluster
- location = clusterMeta.Location
- }
- }
-
- var err error
- kubeconfig, err = ctrl.GetConfig()
- if err != nil {
- fmt.Fprintln(os.Stderr, "Loading kubeconfig failed:", err)
- os.Exit(1)
- }
- if err := setRESTConfigDefaults(kubeconfig); err != nil {
- fmt.Fprintln(os.Stderr, "Setting REST config defaults failed:", err)
- os.Exit(1)
- }
-
- c, err := newClient()
- if err != nil {
- fmt.Fprintln(os.Stderr, "build Kubernetes client:", err)
- os.Exit(1)
- }
-
- if cleanup || cleanupOnly {
- fmt.Fprintln(os.Stdout, "cleaning resources before tests...")
- if err := cleanupResources(context.Background(), kubeconfig, c, ""); err != nil {
- fmt.Fprintln(os.Stderr, "cleaning up failed:", err)
- os.Exit(1)
- }
- if cleanupOnly {
- fmt.Fprintln(os.Stderr, "cleaning up finished")
- os.Exit(0)
- }
- }
-
- /**
- go func() {
- os.Exit(m.Run())
- }()
- **/
-
- // If the process gets terminated by the user, the Go test package
- // doesn't ensure that test cleanup functions are run.
- // Deleting all namespaces ensures we don't leave anything behind regardless.
- // Non-namespaced resources are owned by a namespace and thus cleaned up
- // by Kubernetes' garbage collection.
- term := make(chan os.Signal, 1)
- signal.Notify(term, os.Interrupt, syscall.SIGTERM)
-
- <-term
- if leakResources {
- return
- }
- fmt.Fprintln(os.Stdout, "cleaning up abandoned resources...")
- if err := cleanupResources(context.Background(), kubeconfig, c, ""); err != nil {
- fmt.Fprintln(os.Stderr, "Cleaning up namespaces failed:", err)
- os.Exit(1)
- }
-}
-
-// OperatorContext manages shared state for a group of test which tests interaction
-// of operator and operated resources. OperatorContext mimics cluster with the
-// GMP operator. It runs operator code directly in the background (as opposed to
-// letting Kubernetes run it). It also deploys collector, rule and alertmanager
-// manually for this context.
-//
-// Contexts are isolated based on an unique namespace. This requires that no
-// test affects or can be affected by resources outside the namespace managed by the context.
-// The cluster must be left in a clean state after the cleanup handler completed successfully.
-type OperatorContext struct {
- *testing.T
-
- namespace, pubNamespace, userNamespace string
-
- kClient kubeutil.DelegatingClient
-}
-
-func newOperatorContext(t *testing.T) *OperatorContext {
- c, err := newClient()
- if err != nil {
- t.Fatalf("Build Kubernetes client: %s", err)
- }
-
- ctx, cancel := context.WithCancel(context.Background())
- // Create a namespace per test and run. This is to ensure that repeated runs of
- // tests don't falsify results. Either by old test resources not being cleaned up
- // (less likely) or metrics observed in GCP being from a previous run (more likely).
- namespace := fmt.Sprintf("gmp-test-%s-%s", strings.ToLower(t.Name()), startTime.Format("20060102-150405"))
- pubNamespace := fmt.Sprintf("%s-pub", namespace)
- userNamespace := fmt.Sprintf("%s-user", namespace)
-
- tctx := &OperatorContext{
- T: t,
- namespace: namespace,
- pubNamespace: pubNamespace,
- userNamespace: userNamespace,
- }
- tctx.kClient = kubeutil.NewLabelWriterClient(c, tctx.getSubTestLabels())
- t.Cleanup(func() {
- if !leakResources {
- if err := cleanupResourcesInNamespaces(ctx, kubeconfig, tctx.Client(), []string{namespace, pubNamespace, userNamespace}, tctx.getSubTestLabelValue()); err != nil {
- t.Fatalf("unable to cleanup resources: %s", err)
- }
- }
- cancel()
- })
-
- if err := createBaseResources(ctx, tctx.Client(), namespace, pubNamespace, userNamespace, tctx.GetOperatorTestLabelValue()); err != nil {
- t.Fatalf("create resources: %s", err)
- }
-
- var httpClient *http.Client
- if portForward {
- var err error
- httpClient, err = kubeutil.PortForwardClient(t, kubeconfig, tctx.Client())
- if err != nil {
- t.Fatalf("creating HTTP client: %s", err)
- }
- }
-
- op, err := operator.New(globalLogger, kubeconfig, operator.Options{
- ProjectID: projectID,
- Cluster: cluster,
- Location: location,
- OperatorNamespace: tctx.namespace,
- PublicNamespace: tctx.pubNamespace,
- // Pick a random available port.
- ListenAddr: ":0",
- CollectorHTTPClient: httpClient,
- })
- if err != nil {
- t.Fatalf("instantiating operator: %s", err)
- }
-
- go func() {
- if err := op.Run(ctx, prometheus.NewRegistry()); err != nil {
- // Since we aren't in the main test goroutine we cannot fail with Fatal here.
- t.Errorf("running operator: %s", err)
- }
- }()
-
- return tctx
-}
-
-// createOperatorConfig creates an OperatorConfig, defaulting fields that aren't provided.
-func (tctx *OperatorContext) createOperatorConfigFrom(ctx context.Context, opCfg monitoringv1.OperatorConfig) {
- if opCfg.Name == "" {
- opCfg.Name = operator.NameOperatorConfig
- }
- if opCfg.Namespace == "" {
- opCfg.Namespace = tctx.pubNamespace
- }
-
- if gcpServiceAccount != "" {
- opCfg.Collection.Credentials = &corev1.SecretKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: "user-gcp-service-account",
- },
- Key: "key.json",
- }
- }
-
- // Create a copy which wil represents the current object if it already exists.
- obj := opCfg.DeepCopy()
- if _, err := controllerutil.CreateOrUpdate(ctx, tctx.Client(), obj, func() error {
- // For updates, we need the resource version in the object meta to match. Replace everything else.
- opCfg.ObjectMeta = obj.ObjectMeta
- *obj = opCfg
- return nil
- }); err != nil {
- tctx.Fatalf("create OperatorConfig: %s", err)
- }
-}
-
-func (tctx *OperatorContext) getSubTestLabelValue() string {
- return strings.ReplaceAll(tctx.T.Name(), "/", ".")
-}
-
-func (tctx *OperatorContext) getSubTestLabels() map[string]string {
- return map[string]string{
- testLabel: tctx.getSubTestLabelValue(),
- }
-}
-
-func (tctx *OperatorContext) GetOperatorTestLabelValue() string {
- return strings.SplitN(tctx.T.Name(), "/", 2)[0]
-}
-
-// createBaseResources creates resources the operator requires to exist already.
-// These are resources which don't depend on runtime state and can thus be deployed
-// statically, allowing to run the operator without critical write permissions.
-func createBaseResources(ctx context.Context, kubeClient client.Client, opNamespace, publicNamespace, userNamespace, labelValue string) error {
- if err := createNamespaces(ctx, kubeClient, opNamespace, publicNamespace, userNamespace); err != nil {
- return err
- }
-
- if err := createGCPSecretResources(ctx, kubeClient, opNamespace); err != nil {
- return err
- }
- if err := createCollectorResources(ctx, kubeClient, opNamespace, labelValue); err != nil {
- return err
- }
- if err := createAlertmanagerResources(ctx, kubeClient, opNamespace); err != nil {
- return err
- }
- return nil
-}
-
-func createNamespaces(ctx context.Context, kubeClient client.Client, opNamespace, publicNamespace, userNamespace string) error {
- if err := kubeClient.Create(ctx, &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: opNamespace,
- },
- }); err != nil {
- return err
- }
- if err := kubeClient.Create(ctx, &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: publicNamespace,
- },
- }); err != nil {
- return err
- }
- return kubeClient.Create(ctx, &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: userNamespace,
- },
- })
-}
-
-func createGCPSecretResources(ctx context.Context, kubeClient client.Client, namespace string) error {
- if gcpServiceAccount != "" {
- b, err := os.ReadFile(gcpServiceAccount)
- if err != nil {
- return fmt.Errorf("read GCP service account file: %w", err)
- }
- if err = kubeClient.Create(ctx, &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "user-gcp-service-account",
- Namespace: namespace,
- },
- Data: map[string][]byte{
- "key.json": b,
- },
- }); err != nil {
- return fmt.Errorf("create GCP service account secret: %w", err)
- }
- }
- return nil
-}
-
-func createCollectorResources(ctx context.Context, kubeClient client.Client, namespace, labelValue string) error {
- if err := kubeClient.Create(ctx, &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Name: operator.NameCollector,
- Namespace: namespace,
- },
- }); err != nil {
- return err
- }
-
- // The cluster role expected to exist already.
- const clusterRoleName = operator.DefaultOperatorNamespace + ":" + operator.NameCollector
-
- if err := kubeClient.Create(ctx, &rbacv1.ClusterRoleBinding{
- ObjectMeta: metav1.ObjectMeta{
- Name: clusterRoleName + ":" + namespace,
- },
- RoleRef: rbacv1.RoleRef{
- APIGroup: "rbac.authorization.k8s.io",
- Kind: "ClusterRole",
- // The ClusterRole is expected to exist in the cluster already.
- Name: clusterRoleName,
- },
- Subjects: []rbacv1.Subject{
- {
- Kind: "ServiceAccount",
- Namespace: namespace,
- Name: operator.NameCollector,
- },
- },
- }); err != nil {
- return err
- }
-
- obj, err := kubeutil.ResourceFromFile(kubeClient.Scheme(), collectorManifest)
- if err != nil {
- return fmt.Errorf("decode collector: %w", err)
- }
- collector := obj.(*appsv1.DaemonSet)
- collector.Namespace = namespace
- if collector.Spec.Template.Labels == nil {
- collector.Spec.Template.Labels = map[string]string{}
- }
- collector.Spec.Template.Labels[testLabel] = labelValue
- if skipGCM {
- for i := range collector.Spec.Template.Spec.Containers {
- container := &collector.Spec.Template.Spec.Containers[i]
- if container.Name == "prometheus" {
- container.Args = append(container.Args, "--export.debug.disable-auth")
- break
- }
- }
- }
-
- if err = kubeClient.Create(ctx, collector); err != nil {
- return fmt.Errorf("create collector DaemonSet: %w", err)
- }
- return nil
-}
-
-func createAlertmanagerResources(ctx context.Context, kubeClient client.Client, namespace string) error {
- obj, err := kubeutil.ResourceFromFile(kubeClient.Scheme(), ruleEvalManifest)
- if err != nil {
- return fmt.Errorf("decode evaluator: %w", err)
- }
- evaluator := obj.(*appsv1.Deployment)
- evaluator.Namespace = namespace
-
- if err := kubeClient.Create(ctx, evaluator); err != nil {
- return fmt.Errorf("create rule-evaluator Deployment: %w", err)
- }
-
- objs, err := kubeutil.ResourcesFromFile(kubeClient.Scheme(), alertmanagerManifest)
- if err != nil {
- return fmt.Errorf("read alertmanager YAML: %w", err)
- }
- for i, obj := range objs {
- obj.SetNamespace(namespace)
-
- if err := kubeClient.Create(ctx, obj); err != nil {
- return fmt.Errorf("create object at index %d: %w", i, err)
- }
- }
-
- return nil
-}
-
-func (tctx *OperatorContext) RestConfig() *rest.Config {
- return kubeconfig
-}
-
-func (tctx *OperatorContext) Client() client.Client {
- return tctx.kClient
-}
-
-// subtest derives a new test function from a function accepting a test context.
-func (tctx *OperatorContext) subtest(f func(context.Context, *OperatorContext)) func(*testing.T) {
- return func(t *testing.T) {
- ctx := context.TODO()
- childCtx := *tctx
- childCtx.T = t
- childCtx.kClient = kubeutil.NewLabelWriterClient(tctx.kClient.Base(), childCtx.getSubTestLabels())
- t.Cleanup(func() {
- if leakResources {
- return
- }
- t.Log("cleaning up resources...")
- if err := cleanupResourcesInNamespaces(ctx, kubeconfig, childCtx.Client(), []string{tctx.namespace, tctx.pubNamespace}, childCtx.getSubTestLabelValue()); err != nil {
- t.Fatalf("unable to cleanup resources: %s", err)
- }
- })
- f(ctx, &childCtx)
- }
-}
-
-func getGroupVersionKinds(discoveryClient discovery.DiscoveryInterface) ([]schema.GroupVersionKind, error) {
- _, resources, err := discoveryClient.ServerGroupsAndResources()
- if err != nil {
- return nil, err
- }
- var errs []error
- var gvks []schema.GroupVersionKind
- for _, resource := range resources {
- for _, api := range resource.APIResources {
- gv, err := schema.ParseGroupVersion(resource.GroupVersion)
- if err != nil {
- errs = append(errs, nil)
- continue
- }
- gvks = append(gvks, gv.WithKind(api.Kind))
- }
- }
- return gvks, errors.Join(errs...)
-}
-
-func getNamespaces(ctx context.Context, kubeClient client.Client) ([]string, error) {
- var namespaces []string
- var namespaceList corev1.NamespaceList
- if err := kubeClient.List(ctx, &namespaceList); err != nil {
- return nil, err
- }
- for _, namespace := range namespaceList.Items {
- namespaces = append(namespaces, namespace.Name)
- }
- return namespaces, nil
-}
-
-func isNamespaced(kubeClient client.Client, gvk schema.GroupVersionKind) (bool, error) {
- apiVersion, kind := gvk.ToAPIVersionAndKind()
- obj := metav1.PartialObjectMetadata{
- TypeMeta: metav1.TypeMeta{
- APIVersion: apiVersion,
- Kind: kind,
- },
- }
- return kubeClient.IsObjectNamespaced(&obj)
-}
-
-func labelSelector(labelName, labelValue string) (labels.Selector, error) {
- if labelValue == "" {
- req, err := labels.NewRequirement(labelName, selection.Exists, []string{})
- if err != nil {
- return nil, err
- }
- return labels.NewSelector().Add(*req), nil
- }
- req, err := labels.NewRequirement(labelName, selection.Equals, []string{labelValue})
- if err != nil {
- return nil, err
- }
- return labels.NewSelector().Add(*req), nil
-}
-
-func cleanupResource(ctx context.Context, kubeClient client.Client, gvk schema.GroupVersionKind, labelValue, namespace string) error {
- labelSelector, err := labelSelector(testLabel, labelValue)
- if err != nil {
- return err
- }
- listOpts := client.ListOptions{
- LabelSelector: labelSelector,
- }
- if namespace != "" {
- listOpts.Namespace = namespace
- }
-
- apiVersion, kind := gvk.ToAPIVersionAndKind()
- obj := metav1.PartialObjectMetadata{
- TypeMeta: metav1.TypeMeta{
- APIVersion: apiVersion,
- Kind: kind,
- },
- }
-
- if err := kubeClient.DeleteAllOf(ctx, &obj, &client.DeleteAllOfOptions{
- ListOptions: listOpts,
- }); err != nil {
- if apierrors.IsMethodNotSupported(err) {
- // We are not allowed to touch Kubernetes-managed objects.
- return nil
- }
- // Ignore meta-resource types.
- if errors.Is(err, &meta.NoKindMatchError{GroupKind: gvk.GroupKind()}) {
- return nil
- }
- return fmt.Errorf("unable to delete %s: %w", gvk.String(), err)
- }
- return nil
-}
-
-// cleanupResources cleans all resources created by tests. If no label value is provided,
-// then all resources with the label are removed.
-func cleanupResources(ctx context.Context, restConfig *rest.Config, kubeClient client.Client, labelValue string) error {
- namespaces, err := getNamespaces(ctx, kubeClient)
- if err != nil {
- return err
- }
- return cleanupResourcesInNamespaces(ctx, restConfig, kubeClient, namespaces, labelValue)
-}
-
-func cleanupResourcesInNamespaces(ctx context.Context, restConfig *rest.Config, kubeClient client.Client, namespaces []string, labelValue string) error {
- discoveryClient, err := discovery.NewDiscoveryClientForConfig(restConfig)
- if err != nil {
- return err
- }
- gvks, err := getGroupVersionKinds(discoveryClient)
- if err != nil {
- return err
- }
-
- // The namespaces have to be deleted last, so skip those.
- namespaceGVK := schema.GroupVersionKind{
- Group: "",
- Version: "v1",
- Kind: "Namespace",
- }
-
- var errs []error
- for _, gvk := range gvks {
- if namespaceGVK == gvk {
- continue
- }
- // We don't care about resources that we can't even manage.
- if !kubeClient.Scheme().IsGroupRegistered(gvk.Group) {
- continue
- }
-
- namespaced, err := isNamespaced(kubeClient, gvk)
- if err != nil {
- // Ignore meta-resource types.
- if errors.Is(err, &meta.NoKindMatchError{GroupKind: gvk.GroupKind()}) {
- continue
- }
- errs = append(errs, err)
- }
- if namespaced {
- if labelValue == "" {
- // Skip because deleting the namespace will delete the resource.
- continue
- }
- for _, namespace := range namespaces {
- if err := cleanupResource(ctx, kubeClient, gvk, labelValue, namespace); err != nil {
- errs = append(errs, err)
- }
- }
- } else {
- if err := cleanupResource(ctx, kubeClient, gvk, labelValue, ""); err != nil {
- errs = append(errs, err)
- }
- }
- }
-
- // DeleteAllOf does not work for namespaces, so we must delete individually.
- labelSelector, err := labelSelector(testLabel, labelValue)
- if err != nil {
- return err
- }
- namespaceList := corev1.NamespaceList{}
- if err := kubeClient.List(ctx, &namespaceList, &client.ListOptions{
- LabelSelector: labelSelector,
- }); err != nil {
- return err
- }
- for _, namespace := range namespaceList.Items {
- if err := kubeClient.Delete(ctx, &namespace, &client.DeleteOptions{}); err != nil {
- errs = append(errs, err)
- }
- }
- return errors.Join(errs...)
-}
diff --git a/e2e/operatorutil/collection.go b/e2e/operatorutil/collection.go
deleted file mode 100644
index 90d49c710a..0000000000
--- a/e2e/operatorutil/collection.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package operatorutil
-
-import (
- "context"
-
- "github.com/GoogleCloudPlatform/prometheus-engine/e2e/kubeutil"
- "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func WaitForCollectionReady(ctx context.Context, kubeClient client.Client, operatorNamespace string) error {
- return kubeutil.WaitForDaemonSetReady(ctx, kubeClient, operatorNamespace, operator.NameCollector)
-}
diff --git a/e2e/operatorutil/operatorutil.go b/e2e/operatorutil/operatorutil.go
deleted file mode 100644
index 65bcf58802..0000000000
--- a/e2e/operatorutil/operatorutil.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package operatorutil
-
-import (
- "context"
- "time"
-
- "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/util/wait"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func WaitForOperatorReady(ctx context.Context, kubeClient client.Client, operatorNamespace string) error {
- // Assume that the existence of the config means that the reconcile loop started.
- return wait.PollUntilContextTimeout(ctx, 3*time.Second, 2*time.Minute, true, func(ctx context.Context) (bool, error) {
- var config corev1.ConfigMap
- if err := kubeClient.Get(ctx, client.ObjectKey{Name: operator.NameCollector, Namespace: operatorNamespace}, &config); err != nil {
- return false, nil
- }
- return true, nil
- })
-}
diff --git a/e2e/operatorutil/podmonitoringutil.go b/e2e/operatorutil/podmonitoringutil.go
deleted file mode 100644
index f2fe987c4d..0000000000
--- a/e2e/operatorutil/podmonitoringutil.go
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package operatorutil
-
-import (
- "context"
- "errors"
- "fmt"
- "time"
-
- monitoringv1 "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator/apis/monitoring/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/util/wait"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func IsPodMonitoringReady(pm monitoringv1.PodMonitoringCRD, targetStatusEnabled bool) error {
- for _, condition := range pm.GetStatus().Conditions {
- if condition.Type == monitoringv1.ConfigurationCreateSuccess {
- if condition.Status != corev1.ConditionTrue {
- return fmt.Errorf("configuration was not created successfully: %s", condition.Status)
- }
- } else {
- return fmt.Errorf("unknown condition type: %s", condition.Type)
- }
- }
- if !targetStatusEnabled {
- return nil
- }
- return isPodMonitoringEndpointStatusReady(pm)
-}
-
-func isPodMonitoringEndpointStatusReady(pm monitoringv1.PodMonitoringCRD) error {
- endpointStatuses := pm.GetStatus().EndpointStatuses
- expectedEndpoints := len(pm.GetEndpoints())
- if size := len(endpointStatuses); size == 0 {
- return errors.New("empty endpoint status")
- } else if size != expectedEndpoints {
- return fmt.Errorf("expected %d endpoints, but got: %d", expectedEndpoints, size)
- }
- return nil
-}
-
-func WaitForPodMonitoringReady(ctx context.Context, kubeClient client.Client, operatorNamespace string, pm monitoringv1.PodMonitoringCRD, targetStatusEnabled bool) error {
- if err := WaitForCollectionReady(ctx, kubeClient, operatorNamespace); err != nil {
- return err
- }
-
- timeout := 2 * time.Minute
- interval := 3 * time.Second
- if targetStatusEnabled {
- // Wait for target status to get polled and populated.
- timeout = 4 * time.Minute
- }
-
- var err error
- pollErr := wait.PollUntilContextTimeout(ctx, interval, timeout, true, func(ctx context.Context) (bool, error) {
- if err = kubeClient.Get(ctx, client.ObjectKeyFromObject(pm), pm); err != nil {
- return false, nil
- }
-
- if err = IsPodMonitoringReady(pm, targetStatusEnabled); err != nil {
- return false, nil
- }
- return true, nil
- })
- if pollErr != nil {
- if errors.Is(pollErr, context.DeadlineExceeded) && err != nil {
- return err
- }
- return pollErr
- }
- return nil
-}
-
-func isPodMonitoringScrapeEndpointSuccess(status *monitoringv1.ScrapeEndpointStatus) error {
- var errs []error
- if status.UnhealthyTargets != 0 {
- errs = append(errs, fmt.Errorf("unhealthy targets: %d", status.UnhealthyTargets))
- }
- if status.CollectorsFraction != "1" {
- errs = append(errs, fmt.Errorf("collectors failed: %s", status.CollectorsFraction))
- }
- if len(status.SampleGroups) == 0 {
- errs = append(errs, errors.New("missing sample groups"))
- } else {
- for i, group := range status.SampleGroups {
- if len(group.SampleTargets) == 0 {
- errs = append(errs, fmt.Errorf("missing sample targets for group %d", i))
- } else {
- for _, target := range group.SampleTargets {
- if target.Health != "up" {
- lastErr := "no error reported"
- if target.LastError != nil {
- lastErr = *target.LastError
- }
- errs = append(errs, fmt.Errorf("unhealthy target %q at group %d: %s", target.Health, i, lastErr))
- break
- }
- }
- }
- }
- }
- return errors.Join(errs...)
-}
-
-func isPodMonitoringScrapeEndpointFailure(status *monitoringv1.ScrapeEndpointStatus, expectedFn func(message string) error) error {
- var errs []error
- if status.UnhealthyTargets == 0 {
- errs = append(errs, errors.New("expected no healthy targets"))
- }
- if status.CollectorsFraction == "0" {
- errs = append(errs, fmt.Errorf("expected collectors fraction to be 0 but found: %s", status.CollectorsFraction))
- }
- if len(status.SampleGroups) == 0 {
- errs = append(errs, errors.New("missing sample groups"))
- }
- for i, group := range status.SampleGroups {
- if len(group.SampleTargets) == 0 {
- errs = append(errs, fmt.Errorf("missing sample targets for group %d", i))
- }
- for _, target := range group.SampleTargets {
- if target.Health == "up" {
- errs = append(errs, fmt.Errorf("healthy target %q at group %d", target.Health, i))
- break
- }
- if target.LastError == nil {
- errs = append(errs, fmt.Errorf("missing error for target at group %d", i))
- break
- }
- if err := expectedFn(*target.LastError); err != nil {
- errs = append(errs, fmt.Errorf("for error message %q at group %d: got %w", *target.LastError, i, err))
- break
- }
- }
- }
- return errors.Join(errs...)
-}
-
-func IsPodMonitoringSuccess(pm monitoringv1.PodMonitoringCRD, targetStatusEnabled bool) error {
- if err := IsPodMonitoringReady(pm, targetStatusEnabled); err != nil {
- return err
- }
- if !targetStatusEnabled {
- return nil
- }
- var errs []error
- for _, status := range pm.GetStatus().EndpointStatuses {
- if err := isPodMonitoringScrapeEndpointSuccess(&status); err != nil {
- errs = append(errs, fmt.Errorf("unhealthy endpoint status %q: %w", status.Name, err))
- }
- }
- return errors.Join(errs...)
-}
-
-func WaitForPodMonitoringSuccess(ctx context.Context, kubeClient client.Client, pm monitoringv1.PodMonitoringCRD) error {
- var err error
- if pollErr := wait.PollUntilContextTimeout(ctx, 3*time.Second, 3*time.Minute, true, func(ctx context.Context) (bool, error) {
- if err = kubeClient.Get(ctx, client.ObjectKeyFromObject(pm), pm); err != nil {
- return false, nil
- }
- err = IsPodMonitoringSuccess(pm, true)
- return err == nil, nil
- }); pollErr != nil {
- if errors.Is(pollErr, context.DeadlineExceeded) && err != nil {
- return err
- }
- return pollErr
- }
- return nil
-}
-
-func IsPodMonitoringFailure(pm monitoringv1.PodMonitoringCRD, expectedFn func(message string) error) error {
- if err := IsPodMonitoringReady(pm, expectedFn != nil); err != nil {
- return err
- }
- var errs []error
- for _, status := range pm.GetStatus().EndpointStatuses {
- if err := isPodMonitoringScrapeEndpointFailure(&status, expectedFn); err != nil {
- errs = append(errs, fmt.Errorf("unhealthy endpoint status %q: %w", status.Name, err))
- }
- }
- return errors.Join(errs...)
-}
-
-func WaitForPodMonitoringFailure(ctx context.Context, kubeClient client.Client, pm monitoringv1.PodMonitoringCRD, expectedFn func(message string) error) error {
- var err error
- if pollErr := wait.PollUntilContextTimeout(ctx, 3*time.Second, 3*time.Minute, true, func(ctx context.Context) (bool, error) {
- if err = kubeClient.Get(ctx, client.ObjectKeyFromObject(pm), pm); err != nil {
- return false, nil
- }
- err = IsPodMonitoringFailure(pm, expectedFn)
- return err == nil, nil
- }); pollErr != nil {
- if errors.Is(pollErr, context.DeadlineExceeded) && err != nil {
- return err
- }
- return pollErr
- }
- return nil
-}
diff --git a/e2e/operatorutil/syntheticutil.go b/e2e/operatorutil/syntheticutil.go
deleted file mode 100644
index dcd9f34280..0000000000
--- a/e2e/operatorutil/syntheticutil.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2023 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package operatorutil
-
-import (
- "context"
- "errors"
- "fmt"
-
- "github.com/GoogleCloudPlatform/prometheus-engine/e2e/kubeutil"
- "github.com/GoogleCloudPlatform/prometheus-engine/pkg/operator"
- appsv1 "k8s.io/api/apps/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-const (
- SyntheticAppPortName = "web"
- SyntheticAppContainerName = "go-synthetic"
-
- appManifest = "../examples/instrumentation/go-synthetic/go-synthetic.yaml"
-)
-
-func syntheticAppDeployment(scheme *runtime.Scheme) (*appsv1.Deployment, error) {
- resources, err := kubeutil.ResourcesFromFile(scheme, appManifest)
- if err != nil {
- return nil, err
- }
-
- var deployment *appsv1.Deployment
- for _, resource := range resources {
- var ok bool
- deployment, ok = resource.(*appsv1.Deployment)
- if ok {
- break
- }
- }
- if deployment == nil {
- return nil, errors.New("unable to find app deployment")
- }
- return deployment, nil
-}
-
-func SyntheticAppDeploy(ctx context.Context, kubeClient client.Client, namespace, name string, args []string) (*appsv1.Deployment, error) {
- deployment, err := syntheticAppDeployment(kubeClient.Scheme())
- if err != nil {
- return nil, err
- }
-
- deployment.Namespace = namespace
- deployment.Name = name
- if deployment.Spec.Template.Labels == nil {
- deployment.Spec.Template.Labels = map[string]string{}
- }
- deployment.Spec.Template.Labels[operator.LabelInstanceName] = name
-
- container, err := kubeutil.DeploymentContainer(deployment, SyntheticAppContainerName)
- if err != nil {
- return nil, err
- }
- container.Args = append(container.Args, args...)
-
- if err := kubeClient.Create(ctx, deployment); err != nil {
- return nil, fmt.Errorf("unable to create app deployment: %w", err)
- }
- return deployment, nil
-}
diff --git a/e2e/webhook_test.go b/e2e/webhook_test.go
deleted file mode 100644
index a0d9041ea4..0000000000
--- a/e2e/webhook_test.go
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2022 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package e2e
-
-import (
- "context"
- "errors"
- "fmt"
- "testing"
- "time"
-
- "github.com/GoogleCloudPlatform/prometheus-engine/e2e/operatorutil"
- arv1 "k8s.io/api/admissionregistration/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/wait"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// webhook configurations.
-func TestWebhookCABundleInjection(t *testing.T) {
- t.Parallel()
- tctx := newOperatorContext(t)
-
- var (
- whConfigName = fmt.Sprintf("gmp-operator.%s.monitoring.googleapis.com", tctx.namespace)
- policy = arv1.Ignore // Prevent collisions with other test or real usage
- sideEffects = arv1.SideEffectClassNone
- url = "https://0.1.2.3/"
- )
-
- t.Run("validating webhook", tctx.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
- // Create webhook configs. The operator must populate their caBundles.
- vwc := &arv1.ValidatingWebhookConfiguration{
- ObjectMeta: metav1.ObjectMeta{
- Name: whConfigName,
- },
- Webhooks: []arv1.ValidatingWebhook{
- {
- Name: "wh1.monitoring.googleapis.com",
- ClientConfig: arv1.WebhookClientConfig{URL: &url},
- FailurePolicy: &policy,
- SideEffects: &sideEffects,
- AdmissionReviewVersions: []string{"v1"},
- }, {
- Name: "wh2.monitoring.googleapis.com",
- ClientConfig: arv1.WebhookClientConfig{URL: &url},
- FailurePolicy: &policy,
- SideEffects: &sideEffects,
- AdmissionReviewVersions: []string{"v1"},
- },
- },
- }
- if err := tctx.Client().Create(ctx, vwc); err != nil {
- t.Fatal(err)
- }
-
- if err := operatorutil.WaitForOperatorReady(ctx, t.Client(), t.namespace); err != nil {
- t.Fatal(err)
- }
-
- // Wait for caBundle injection.
- var err error
- waitErr := wait.PollUntilContextTimeout(ctx, 3*time.Second, 4*time.Minute, true, func(ctx context.Context) (bool, error) {
- if err = tctx.Client().Get(ctx, client.ObjectKeyFromObject(vwc), vwc); err != nil {
- return false, nil
- }
- if len(vwc.Webhooks) != 2 {
- return false, fmt.Errorf("expected 2 webhooks but got %d", len(vwc.Webhooks))
- }
- for i, wh := range vwc.Webhooks {
- if len(wh.ClientConfig.CABundle) == 0 {
- err = fmt.Errorf("webhook %d has no CA bundle", i)
- return false, nil
- }
- }
- return true, nil
- })
- if waitErr != nil {
- if errors.Is(waitErr, context.DeadlineExceeded) && err != nil {
- waitErr = err
- }
- t.Fatalf("waiting for ValidatingWebhook CA bundle failed: %s", waitErr)
- }
- }))
-
- t.Run("mutating webhook", tctx.subtest(func(ctx context.Context, t *OperatorContext) {
- t.Parallel()
- // Create webhook configs. The operator must populate their caBundles.
- mwc := &arv1.MutatingWebhookConfiguration{
- ObjectMeta: metav1.ObjectMeta{
- Name: whConfigName,
- },
- Webhooks: []arv1.MutatingWebhook{
- {
- Name: "wh1.monitoring.googleapis.com",
- ClientConfig: arv1.WebhookClientConfig{URL: &url},
- FailurePolicy: &policy,
- SideEffects: &sideEffects,
- AdmissionReviewVersions: []string{"v1"},
- }, {
- Name: "wh2.monitoring.googleapis.com",
- ClientConfig: arv1.WebhookClientConfig{URL: &url},
- FailurePolicy: &policy,
- SideEffects: &sideEffects,
- AdmissionReviewVersions: []string{"v1"},
- },
- },
- }
- if err := tctx.Client().Create(ctx, mwc); err != nil {
- t.Fatal(err)
- }
-
- if err := operatorutil.WaitForOperatorReady(ctx, t.Client(), t.namespace); err != nil {
- t.Fatal(err)
- }
-
- // Wait for caBundle injection.
- var err error
- waitErr := wait.PollUntilContextTimeout(ctx, 3*time.Second, 4*time.Minute, true, func(ctx context.Context) (bool, error) {
- if err = tctx.Client().Get(ctx, client.ObjectKeyFromObject(mwc), mwc); err != nil {
- return false, nil
- }
- if len(mwc.Webhooks) != 2 {
- return false, fmt.Errorf("expected 2 webhooks but got %d", len(mwc.Webhooks))
- }
- for i, wh := range mwc.Webhooks {
- if len(wh.ClientConfig.CABundle) == 0 {
- err = fmt.Errorf("webhook %d has no CA bundle", i)
- return false, nil
- }
- }
- return true, nil
- })
- if waitErr != nil {
- if errors.Is(waitErr, context.DeadlineExceeded) && err != nil {
- waitErr = err
- }
- t.Fatalf("waiting for MutatingWebhook CA bundle failed: %s", waitErr)
- }
- }))
-}
diff --git a/go.mod b/go.mod
index 61115bca00..b92329f426 100644
--- a/go.mod
+++ b/go.mod
@@ -87,12 +87,10 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
- github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
- github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/alertmanager v0.25.1 // indirect
diff --git a/go.sum b/go.sum
index 5c494d2304..8b3f969981 100644
--- a/go.sum
+++ b/go.sum
@@ -72,8 +72,6 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
@@ -318,7 +316,6 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/gophercloud/gophercloud v1.2.0 h1:1oXyj4g54KBg/kFtCdMM6jtxSzeIyg8wv4z1HoGPp1E=
github.com/gophercloud/gophercloud v1.2.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
-github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grafana/grafana-api-golang-client v0.27.0 h1:zIwMXcbCB4n588i3O2N6HfNcQogCNTd/vPkEXTr7zX8=
@@ -424,8 +421,6 @@ github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
-github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -439,8 +434,6 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
diff --git a/hack/kind-test.sh b/hack/kind-test.sh
index e517ea8d51..2bfd711767 100755
--- a/hack/kind-test.sh
+++ b/hack/kind-test.sh
@@ -137,6 +137,9 @@ docker_tag_push() {
update_manifests() {
for bin in "$@"; do
find manifests -type f -name "*.yaml" -exec sed -i "s#image: .*/${bin}:.*#image: localhost:${REGISTRY_PORT}/${bin}:${TAG_NAME}#g" {} \;
+ if [ "$bin" = "go-synthetic" ]; then
+ find examples/instrumentation -type f -name "*.yaml" -exec sed -i "s#image: .*/example-app:.*#image: localhost:${REGISTRY_PORT}/${bin}:${TAG_NAME}#g" {} \;
+ fi
done
}
diff --git a/vendor/github.com/moby/spdystream/CONTRIBUTING.md b/vendor/github.com/moby/spdystream/CONTRIBUTING.md
deleted file mode 100644
index d4eddcc539..0000000000
--- a/vendor/github.com/moby/spdystream/CONTRIBUTING.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Contributing to SpdyStream
-
-Want to hack on spdystream? Awesome! Here are instructions to get you
-started.
-
-SpdyStream is a part of the [Docker](https://docker.io) project, and follows
-the same rules and principles. If you're already familiar with the way
-Docker does things, you'll feel right at home.
-
-Otherwise, go read
-[Docker's contributions guidelines](https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md).
-
-Happy hacking!
diff --git a/vendor/github.com/moby/spdystream/LICENSE b/vendor/github.com/moby/spdystream/LICENSE
deleted file mode 100644
index d645695673..0000000000
--- a/vendor/github.com/moby/spdystream/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/moby/spdystream/MAINTAINERS b/vendor/github.com/moby/spdystream/MAINTAINERS
deleted file mode 100644
index 26e5ec828a..0000000000
--- a/vendor/github.com/moby/spdystream/MAINTAINERS
+++ /dev/null
@@ -1,40 +0,0 @@
-# Spdystream maintainers file
-#
-# This file describes who runs the moby/spdystream project and how.
-# This is a living document - if you see something out of date or missing, speak up!
-#
-# It is structured to be consumable by both humans and programs.
-# To extract its contents programmatically, use any TOML-compliant parser.
-#
-# This file is compiled into the MAINTAINERS file in docker/opensource.
-#
-[Org]
- [Org."Core maintainers"]
- people = [
- "adisky",
- "dims",
- "dmcgowan",
- ]
-
-[people]
-
-# A reference list of all people associated with the project.
-# All other sections should refer to people by their canonical key
-# in the people section.
-
- # ADD YOURSELF HERE IN ALPHABETICAL ORDER
-
- [people.adisky]
- Name = "Aditi Sharma"
- Email = "adi.sky17@gmail.com"
- GitHub = "adisky"
-
- [people.dims]
- Name = "Davanum Srinivas"
- Email = "davanum@gmail.com"
- GitHub = "dims"
-
- [people.dmcgowan]
- Name = "Derek McGowan"
- Email = "derek@mcg.dev"
- GitHub = "dmcgowan"
diff --git a/vendor/github.com/moby/spdystream/NOTICE b/vendor/github.com/moby/spdystream/NOTICE
deleted file mode 100644
index b9b11c9ab7..0000000000
--- a/vendor/github.com/moby/spdystream/NOTICE
+++ /dev/null
@@ -1,5 +0,0 @@
-SpdyStream
-Copyright 2014-2021 Docker Inc.
-
-This product includes software developed at
-Docker Inc. (https://www.docker.com/).
diff --git a/vendor/github.com/moby/spdystream/README.md b/vendor/github.com/moby/spdystream/README.md
deleted file mode 100644
index b84e983439..0000000000
--- a/vendor/github.com/moby/spdystream/README.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# SpdyStream
-
-A multiplexed stream library using spdy
-
-## Usage
-
-Client example (connecting to mirroring server without auth)
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/moby/spdystream"
- "net"
- "net/http"
-)
-
-func main() {
- conn, err := net.Dial("tcp", "localhost:8080")
- if err != nil {
- panic(err)
- }
- spdyConn, err := spdystream.NewConnection(conn, false)
- if err != nil {
- panic(err)
- }
- go spdyConn.Serve(spdystream.NoOpStreamHandler)
- stream, err := spdyConn.CreateStream(http.Header{}, nil, false)
- if err != nil {
- panic(err)
- }
-
- stream.Wait()
-
- fmt.Fprint(stream, "Writing to stream")
-
- buf := make([]byte, 25)
- stream.Read(buf)
- fmt.Println(string(buf))
-
- stream.Close()
-}
-```
-
-Server example (mirroring server without auth)
-
-```go
-package main
-
-import (
- "github.com/moby/spdystream"
- "net"
-)
-
-func main() {
- listener, err := net.Listen("tcp", "localhost:8080")
- if err != nil {
- panic(err)
- }
- for {
- conn, err := listener.Accept()
- if err != nil {
- panic(err)
- }
- spdyConn, err := spdystream.NewConnection(conn, true)
- if err != nil {
- panic(err)
- }
- go spdyConn.Serve(spdystream.MirrorStreamHandler)
- }
-}
-```
-
-## Copyright and license
-
-Copyright 2013-2021 Docker, inc. Released under the [Apache 2.0 license](LICENSE).
diff --git a/vendor/github.com/moby/spdystream/connection.go b/vendor/github.com/moby/spdystream/connection.go
deleted file mode 100644
index d906bb05ce..0000000000
--- a/vendor/github.com/moby/spdystream/connection.go
+++ /dev/null
@@ -1,972 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package spdystream
-
-import (
- "errors"
- "fmt"
- "io"
- "net"
- "net/http"
- "sync"
- "time"
-
- "github.com/moby/spdystream/spdy"
-)
-
-var (
- ErrInvalidStreamId = errors.New("Invalid stream id")
- ErrTimeout = errors.New("Timeout occurred")
- ErrReset = errors.New("Stream reset")
- ErrWriteClosedStream = errors.New("Write on closed stream")
-)
-
-const (
- FRAME_WORKERS = 5
- QUEUE_SIZE = 50
-)
-
-type StreamHandler func(stream *Stream)
-
-type AuthHandler func(header http.Header, slot uint8, parent uint32) bool
-
-type idleAwareFramer struct {
- f *spdy.Framer
- conn *Connection
- writeLock sync.Mutex
- resetChan chan struct{}
- setTimeoutLock sync.Mutex
- setTimeoutChan chan time.Duration
- timeout time.Duration
-}
-
-func newIdleAwareFramer(framer *spdy.Framer) *idleAwareFramer {
- iaf := &idleAwareFramer{
- f: framer,
- resetChan: make(chan struct{}, 2),
- // setTimeoutChan needs to be buffered to avoid deadlocks when calling setIdleTimeout at about
- // the same time the connection is being closed
- setTimeoutChan: make(chan time.Duration, 1),
- }
- return iaf
-}
-
-func (i *idleAwareFramer) monitor() {
- var (
- timer *time.Timer
- expired <-chan time.Time
- resetChan = i.resetChan
- setTimeoutChan = i.setTimeoutChan
- )
-Loop:
- for {
- select {
- case timeout := <-i.setTimeoutChan:
- i.timeout = timeout
- if timeout == 0 {
- if timer != nil {
- timer.Stop()
- }
- } else {
- if timer == nil {
- timer = time.NewTimer(timeout)
- expired = timer.C
- } else {
- timer.Reset(timeout)
- }
- }
- case <-resetChan:
- if timer != nil && i.timeout > 0 {
- timer.Reset(i.timeout)
- }
- case <-expired:
- i.conn.streamCond.L.Lock()
- streams := i.conn.streams
- i.conn.streams = make(map[spdy.StreamId]*Stream)
- i.conn.streamCond.Broadcast()
- i.conn.streamCond.L.Unlock()
- go func() {
- for _, stream := range streams {
- stream.resetStream()
- }
- i.conn.Close()
- }()
- case <-i.conn.closeChan:
- if timer != nil {
- timer.Stop()
- }
-
- // Start a goroutine to drain resetChan. This is needed because we've seen
- // some unit tests with large numbers of goroutines get into a situation
- // where resetChan fills up, at least 1 call to Write() is still trying to
- // send to resetChan, the connection gets closed, and this case statement
- // attempts to grab the write lock that Write() already has, causing a
- // deadlock.
- //
- // See https://github.com/moby/spdystream/issues/49 for more details.
- go func() {
- for range resetChan {
- }
- }()
-
- go func() {
- for range setTimeoutChan {
- }
- }()
-
- i.writeLock.Lock()
- close(resetChan)
- i.resetChan = nil
- i.writeLock.Unlock()
-
- i.setTimeoutLock.Lock()
- close(i.setTimeoutChan)
- i.setTimeoutChan = nil
- i.setTimeoutLock.Unlock()
-
- break Loop
- }
- }
-
- // Drain resetChan
- for range resetChan {
- }
-}
-
-func (i *idleAwareFramer) WriteFrame(frame spdy.Frame) error {
- i.writeLock.Lock()
- defer i.writeLock.Unlock()
- if i.resetChan == nil {
- return io.EOF
- }
- err := i.f.WriteFrame(frame)
- if err != nil {
- return err
- }
-
- i.resetChan <- struct{}{}
-
- return nil
-}
-
-func (i *idleAwareFramer) ReadFrame() (spdy.Frame, error) {
- frame, err := i.f.ReadFrame()
- if err != nil {
- return nil, err
- }
-
- // resetChan should never be closed since it is only closed
- // when the connection has closed its closeChan. This closure
- // only occurs after all Reads have finished
- // TODO (dmcgowan): refactor relationship into connection
- i.resetChan <- struct{}{}
-
- return frame, nil
-}
-
-func (i *idleAwareFramer) setIdleTimeout(timeout time.Duration) {
- i.setTimeoutLock.Lock()
- defer i.setTimeoutLock.Unlock()
-
- if i.setTimeoutChan == nil {
- return
- }
-
- i.setTimeoutChan <- timeout
-}
-
-type Connection struct {
- conn net.Conn
- framer *idleAwareFramer
-
- closeChan chan bool
- goneAway bool
- lastStreamChan chan<- *Stream
- goAwayTimeout time.Duration
- closeTimeout time.Duration
-
- streamLock *sync.RWMutex
- streamCond *sync.Cond
- streams map[spdy.StreamId]*Stream
-
- nextIdLock sync.Mutex
- receiveIdLock sync.Mutex
- nextStreamId spdy.StreamId
- receivedStreamId spdy.StreamId
-
- pingIdLock sync.Mutex
- pingId uint32
- pingChans map[uint32]chan error
-
- shutdownLock sync.Mutex
- shutdownChan chan error
- hasShutdown bool
-
- // for testing https://github.com/moby/spdystream/pull/56
- dataFrameHandler func(*spdy.DataFrame) error
-}
-
-// NewConnection creates a new spdy connection from an existing
-// network connection.
-func NewConnection(conn net.Conn, server bool) (*Connection, error) {
- framer, framerErr := spdy.NewFramer(conn, conn)
- if framerErr != nil {
- return nil, framerErr
- }
- idleAwareFramer := newIdleAwareFramer(framer)
- var sid spdy.StreamId
- var rid spdy.StreamId
- var pid uint32
- if server {
- sid = 2
- rid = 1
- pid = 2
- } else {
- sid = 1
- rid = 2
- pid = 1
- }
-
- streamLock := new(sync.RWMutex)
- streamCond := sync.NewCond(streamLock)
-
- session := &Connection{
- conn: conn,
- framer: idleAwareFramer,
-
- closeChan: make(chan bool),
- goAwayTimeout: time.Duration(0),
- closeTimeout: time.Duration(0),
-
- streamLock: streamLock,
- streamCond: streamCond,
- streams: make(map[spdy.StreamId]*Stream),
- nextStreamId: sid,
- receivedStreamId: rid,
-
- pingId: pid,
- pingChans: make(map[uint32]chan error),
-
- shutdownChan: make(chan error),
- }
- session.dataFrameHandler = session.handleDataFrame
- idleAwareFramer.conn = session
- go idleAwareFramer.monitor()
-
- return session, nil
-}
-
-// Ping sends a ping frame across the connection and
-// returns the response time
-func (s *Connection) Ping() (time.Duration, error) {
- pid := s.pingId
- s.pingIdLock.Lock()
- if s.pingId > 0x7ffffffe {
- s.pingId = s.pingId - 0x7ffffffe
- } else {
- s.pingId = s.pingId + 2
- }
- s.pingIdLock.Unlock()
- pingChan := make(chan error)
- s.pingChans[pid] = pingChan
- defer delete(s.pingChans, pid)
-
- frame := &spdy.PingFrame{Id: pid}
- startTime := time.Now()
- writeErr := s.framer.WriteFrame(frame)
- if writeErr != nil {
- return time.Duration(0), writeErr
- }
- select {
- case <-s.closeChan:
- return time.Duration(0), errors.New("connection closed")
- case err, ok := <-pingChan:
- if ok && err != nil {
- return time.Duration(0), err
- }
- break
- }
- return time.Since(startTime), nil
-}
-
-// Serve handles frames sent from the server, including reply frames
-// which are needed to fully initiate connections. Both clients and servers
-// should call Serve in a separate goroutine before creating streams.
-func (s *Connection) Serve(newHandler StreamHandler) {
- // use a WaitGroup to wait for all frames to be drained after receiving
- // go-away.
- var wg sync.WaitGroup
-
- // Parition queues to ensure stream frames are handled
- // by the same worker, ensuring order is maintained
- frameQueues := make([]*PriorityFrameQueue, FRAME_WORKERS)
- for i := 0; i < FRAME_WORKERS; i++ {
- frameQueues[i] = NewPriorityFrameQueue(QUEUE_SIZE)
-
- // Ensure frame queue is drained when connection is closed
- go func(frameQueue *PriorityFrameQueue) {
- <-s.closeChan
- frameQueue.Drain()
- }(frameQueues[i])
-
- wg.Add(1)
- go func(frameQueue *PriorityFrameQueue) {
- // let the WaitGroup know this worker is done
- defer wg.Done()
-
- s.frameHandler(frameQueue, newHandler)
- }(frameQueues[i])
- }
-
- var (
- partitionRoundRobin int
- goAwayFrame *spdy.GoAwayFrame
- )
-Loop:
- for {
- readFrame, err := s.framer.ReadFrame()
- if err != nil {
- if err != io.EOF {
- debugMessage("frame read error: %s", err)
- } else {
- debugMessage("(%p) EOF received", s)
- }
- break
- }
- var priority uint8
- var partition int
- switch frame := readFrame.(type) {
- case *spdy.SynStreamFrame:
- if s.checkStreamFrame(frame) {
- priority = frame.Priority
- partition = int(frame.StreamId % FRAME_WORKERS)
- debugMessage("(%p) Add stream frame: %d ", s, frame.StreamId)
- s.addStreamFrame(frame)
- } else {
- debugMessage("(%p) Rejected stream frame: %d ", s, frame.StreamId)
- continue
- }
- case *spdy.SynReplyFrame:
- priority = s.getStreamPriority(frame.StreamId)
- partition = int(frame.StreamId % FRAME_WORKERS)
- case *spdy.DataFrame:
- priority = s.getStreamPriority(frame.StreamId)
- partition = int(frame.StreamId % FRAME_WORKERS)
- case *spdy.RstStreamFrame:
- priority = s.getStreamPriority(frame.StreamId)
- partition = int(frame.StreamId % FRAME_WORKERS)
- case *spdy.HeadersFrame:
- priority = s.getStreamPriority(frame.StreamId)
- partition = int(frame.StreamId % FRAME_WORKERS)
- case *spdy.PingFrame:
- priority = 0
- partition = partitionRoundRobin
- partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
- case *spdy.GoAwayFrame:
- // hold on to the go away frame and exit the loop
- goAwayFrame = frame
- break Loop
- default:
- priority = 7
- partition = partitionRoundRobin
- partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
- }
- frameQueues[partition].Push(readFrame, priority)
- }
- close(s.closeChan)
-
- // wait for all frame handler workers to indicate they've drained their queues
- // before handling the go away frame
- wg.Wait()
-
- if goAwayFrame != nil {
- s.handleGoAwayFrame(goAwayFrame)
- }
-
- // now it's safe to close remote channels and empty s.streams
- s.streamCond.L.Lock()
- // notify streams that they're now closed, which will
- // unblock any stream Read() calls
- for _, stream := range s.streams {
- stream.closeRemoteChannels()
- }
- s.streams = make(map[spdy.StreamId]*Stream)
- s.streamCond.Broadcast()
- s.streamCond.L.Unlock()
-}
-
-func (s *Connection) frameHandler(frameQueue *PriorityFrameQueue, newHandler StreamHandler) {
- for {
- popFrame := frameQueue.Pop()
- if popFrame == nil {
- return
- }
-
- var frameErr error
- switch frame := popFrame.(type) {
- case *spdy.SynStreamFrame:
- frameErr = s.handleStreamFrame(frame, newHandler)
- case *spdy.SynReplyFrame:
- frameErr = s.handleReplyFrame(frame)
- case *spdy.DataFrame:
- frameErr = s.dataFrameHandler(frame)
- case *spdy.RstStreamFrame:
- frameErr = s.handleResetFrame(frame)
- case *spdy.HeadersFrame:
- frameErr = s.handleHeaderFrame(frame)
- case *spdy.PingFrame:
- frameErr = s.handlePingFrame(frame)
- case *spdy.GoAwayFrame:
- frameErr = s.handleGoAwayFrame(frame)
- default:
- frameErr = fmt.Errorf("unhandled frame type: %T", frame)
- }
-
- if frameErr != nil {
- debugMessage("frame handling error: %s", frameErr)
- }
- }
-}
-
-func (s *Connection) getStreamPriority(streamId spdy.StreamId) uint8 {
- stream, streamOk := s.getStream(streamId)
- if !streamOk {
- return 7
- }
- return stream.priority
-}
-
-func (s *Connection) addStreamFrame(frame *spdy.SynStreamFrame) {
- var parent *Stream
- if frame.AssociatedToStreamId != spdy.StreamId(0) {
- parent, _ = s.getStream(frame.AssociatedToStreamId)
- }
-
- stream := &Stream{
- streamId: frame.StreamId,
- parent: parent,
- conn: s,
- startChan: make(chan error),
- headers: frame.Headers,
- finished: (frame.CFHeader.Flags & spdy.ControlFlagUnidirectional) != 0x00,
- replyCond: sync.NewCond(new(sync.Mutex)),
- dataChan: make(chan []byte),
- headerChan: make(chan http.Header),
- closeChan: make(chan bool),
- priority: frame.Priority,
- }
- if frame.CFHeader.Flags&spdy.ControlFlagFin != 0x00 {
- stream.closeRemoteChannels()
- }
-
- s.addStream(stream)
-}
-
-// checkStreamFrame checks to see if a stream frame is allowed.
-// If the stream is invalid, then a reset frame with protocol error
-// will be returned.
-func (s *Connection) checkStreamFrame(frame *spdy.SynStreamFrame) bool {
- s.receiveIdLock.Lock()
- defer s.receiveIdLock.Unlock()
- if s.goneAway {
- return false
- }
- validationErr := s.validateStreamId(frame.StreamId)
- if validationErr != nil {
- go func() {
- resetErr := s.sendResetFrame(spdy.ProtocolError, frame.StreamId)
- if resetErr != nil {
- debugMessage("reset error: %s", resetErr)
- }
- }()
- return false
- }
- return true
-}
-
-func (s *Connection) handleStreamFrame(frame *spdy.SynStreamFrame, newHandler StreamHandler) error {
- stream, ok := s.getStream(frame.StreamId)
- if !ok {
- return fmt.Errorf("Missing stream: %d", frame.StreamId)
- }
-
- newHandler(stream)
-
- return nil
-}
-
-func (s *Connection) handleReplyFrame(frame *spdy.SynReplyFrame) error {
- debugMessage("(%p) Reply frame received for %d", s, frame.StreamId)
- stream, streamOk := s.getStream(frame.StreamId)
- if !streamOk {
- debugMessage("Reply frame gone away for %d", frame.StreamId)
- // Stream has already gone away
- return nil
- }
- if stream.replied {
- // Stream has already received reply
- return nil
- }
- stream.replied = true
-
- // TODO Check for error
- if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 {
- s.remoteStreamFinish(stream)
- }
-
- close(stream.startChan)
-
- return nil
-}
-
-func (s *Connection) handleResetFrame(frame *spdy.RstStreamFrame) error {
- stream, streamOk := s.getStream(frame.StreamId)
- if !streamOk {
- // Stream has already been removed
- return nil
- }
- s.removeStream(stream)
- stream.closeRemoteChannels()
-
- if !stream.replied {
- stream.replied = true
- stream.startChan <- ErrReset
- close(stream.startChan)
- }
-
- stream.finishLock.Lock()
- stream.finished = true
- stream.finishLock.Unlock()
-
- return nil
-}
-
-func (s *Connection) handleHeaderFrame(frame *spdy.HeadersFrame) error {
- stream, streamOk := s.getStream(frame.StreamId)
- if !streamOk {
- // Stream has already gone away
- return nil
- }
- if !stream.replied {
- // No reply received...Protocol error?
- return nil
- }
-
- // TODO limit headers while not blocking (use buffered chan or goroutine?)
- select {
- case <-stream.closeChan:
- return nil
- case stream.headerChan <- frame.Headers:
- }
-
- if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 {
- s.remoteStreamFinish(stream)
- }
-
- return nil
-}
-
-func (s *Connection) handleDataFrame(frame *spdy.DataFrame) error {
- debugMessage("(%p) Data frame received for %d", s, frame.StreamId)
- stream, streamOk := s.getStream(frame.StreamId)
- if !streamOk {
- debugMessage("(%p) Data frame gone away for %d", s, frame.StreamId)
- // Stream has already gone away
- return nil
- }
- if !stream.replied {
- debugMessage("(%p) Data frame not replied %d", s, frame.StreamId)
- // No reply received...Protocol error?
- return nil
- }
-
- debugMessage("(%p) (%d) Data frame handling", stream, stream.streamId)
- if len(frame.Data) > 0 {
- stream.dataLock.RLock()
- select {
- case <-stream.closeChan:
- debugMessage("(%p) (%d) Data frame not sent (stream shut down)", stream, stream.streamId)
- case stream.dataChan <- frame.Data:
- debugMessage("(%p) (%d) Data frame sent", stream, stream.streamId)
- }
- stream.dataLock.RUnlock()
- }
- if (frame.Flags & spdy.DataFlagFin) != 0x00 {
- s.remoteStreamFinish(stream)
- }
- return nil
-}
-
-func (s *Connection) handlePingFrame(frame *spdy.PingFrame) error {
- if s.pingId&0x01 != frame.Id&0x01 {
- return s.framer.WriteFrame(frame)
- }
- pingChan, pingOk := s.pingChans[frame.Id]
- if pingOk {
- close(pingChan)
- }
- return nil
-}
-
-func (s *Connection) handleGoAwayFrame(frame *spdy.GoAwayFrame) error {
- debugMessage("(%p) Go away received", s)
- s.receiveIdLock.Lock()
- if s.goneAway {
- s.receiveIdLock.Unlock()
- return nil
- }
- s.goneAway = true
- s.receiveIdLock.Unlock()
-
- if s.lastStreamChan != nil {
- stream, _ := s.getStream(frame.LastGoodStreamId)
- go func() {
- s.lastStreamChan <- stream
- }()
- }
-
- // Do not block frame handler waiting for closure
- go s.shutdown(s.goAwayTimeout)
-
- return nil
-}
-
-func (s *Connection) remoteStreamFinish(stream *Stream) {
- stream.closeRemoteChannels()
-
- stream.finishLock.Lock()
- if stream.finished {
- // Stream is fully closed, cleanup
- s.removeStream(stream)
- }
- stream.finishLock.Unlock()
-}
-
-// CreateStream creates a new spdy stream using the parameters for
-// creating the stream frame. The stream frame will be sent upon
-// calling this function, however this function does not wait for
-// the reply frame. If waiting for the reply is desired, use
-// the stream Wait or WaitTimeout function on the stream returned
-// by this function.
-func (s *Connection) CreateStream(headers http.Header, parent *Stream, fin bool) (*Stream, error) {
- // MUST synchronize stream creation (all the way to writing the frame)
- // as stream IDs **MUST** increase monotonically.
- s.nextIdLock.Lock()
- defer s.nextIdLock.Unlock()
-
- streamId := s.getNextStreamId()
- if streamId == 0 {
- return nil, fmt.Errorf("Unable to get new stream id")
- }
-
- stream := &Stream{
- streamId: streamId,
- parent: parent,
- conn: s,
- startChan: make(chan error),
- headers: headers,
- dataChan: make(chan []byte),
- headerChan: make(chan http.Header),
- closeChan: make(chan bool),
- }
-
- debugMessage("(%p) (%p) Create stream", s, stream)
-
- s.addStream(stream)
-
- return stream, s.sendStream(stream, fin)
-}
-
-func (s *Connection) shutdown(closeTimeout time.Duration) {
- // TODO Ensure this isn't called multiple times
- s.shutdownLock.Lock()
- if s.hasShutdown {
- s.shutdownLock.Unlock()
- return
- }
- s.hasShutdown = true
- s.shutdownLock.Unlock()
-
- var timeout <-chan time.Time
- if closeTimeout > time.Duration(0) {
- timeout = time.After(closeTimeout)
- }
- streamsClosed := make(chan bool)
-
- go func() {
- s.streamCond.L.Lock()
- for len(s.streams) > 0 {
- debugMessage("Streams opened: %d, %#v", len(s.streams), s.streams)
- s.streamCond.Wait()
- }
- s.streamCond.L.Unlock()
- close(streamsClosed)
- }()
-
- var err error
- select {
- case <-streamsClosed:
- // No active streams, close should be safe
- err = s.conn.Close()
- case <-timeout:
- // Force ungraceful close
- err = s.conn.Close()
- // Wait for cleanup to clear active streams
- <-streamsClosed
- }
-
- if err != nil {
- duration := 10 * time.Minute
- time.AfterFunc(duration, func() {
- select {
- case err, ok := <-s.shutdownChan:
- if ok {
- debugMessage("Unhandled close error after %s: %s", duration, err)
- }
- default:
- }
- })
- s.shutdownChan <- err
- }
- close(s.shutdownChan)
-}
-
-// Closes spdy connection by sending GoAway frame and initiating shutdown
-func (s *Connection) Close() error {
- s.receiveIdLock.Lock()
- if s.goneAway {
- s.receiveIdLock.Unlock()
- return nil
- }
- s.goneAway = true
- s.receiveIdLock.Unlock()
-
- var lastStreamId spdy.StreamId
- if s.receivedStreamId > 2 {
- lastStreamId = s.receivedStreamId - 2
- }
-
- goAwayFrame := &spdy.GoAwayFrame{
- LastGoodStreamId: lastStreamId,
- Status: spdy.GoAwayOK,
- }
-
- err := s.framer.WriteFrame(goAwayFrame)
- go s.shutdown(s.closeTimeout)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-// CloseWait closes the connection and waits for shutdown
-// to finish. Note the underlying network Connection
-// is not closed until the end of shutdown.
-func (s *Connection) CloseWait() error {
- closeErr := s.Close()
- if closeErr != nil {
- return closeErr
- }
- shutdownErr, ok := <-s.shutdownChan
- if ok {
- return shutdownErr
- }
- return nil
-}
-
-// Wait waits for the connection to finish shutdown or for
-// the wait timeout duration to expire. This needs to be
-// called either after Close has been called or the GOAWAYFRAME
-// has been received. If the wait timeout is 0, this function
-// will block until shutdown finishes. If wait is never called
-// and a shutdown error occurs, that error will be logged as an
-// unhandled error.
-func (s *Connection) Wait(waitTimeout time.Duration) error {
- var timeout <-chan time.Time
- if waitTimeout > time.Duration(0) {
- timeout = time.After(waitTimeout)
- }
-
- select {
- case err, ok := <-s.shutdownChan:
- if ok {
- return err
- }
- case <-timeout:
- return ErrTimeout
- }
- return nil
-}
-
-// NotifyClose registers a channel to be called when the remote
-// peer inidicates connection closure. The last stream to be
-// received by the remote will be sent on the channel. The notify
-// timeout will determine the duration between go away received
-// and the connection being closed.
-func (s *Connection) NotifyClose(c chan<- *Stream, timeout time.Duration) {
- s.goAwayTimeout = timeout
- s.lastStreamChan = c
-}
-
-// SetCloseTimeout sets the amount of time close will wait for
-// streams to finish before terminating the underlying network
-// connection. Setting the timeout to 0 will cause close to
-// wait forever, which is the default.
-func (s *Connection) SetCloseTimeout(timeout time.Duration) {
- s.closeTimeout = timeout
-}
-
-// SetIdleTimeout sets the amount of time the connection may sit idle before
-// it is forcefully terminated.
-func (s *Connection) SetIdleTimeout(timeout time.Duration) {
- s.framer.setIdleTimeout(timeout)
-}
-
-func (s *Connection) sendHeaders(headers http.Header, stream *Stream, fin bool) error {
- var flags spdy.ControlFlags
- if fin {
- flags = spdy.ControlFlagFin
- }
-
- headerFrame := &spdy.HeadersFrame{
- StreamId: stream.streamId,
- Headers: headers,
- CFHeader: spdy.ControlFrameHeader{Flags: flags},
- }
-
- return s.framer.WriteFrame(headerFrame)
-}
-
-func (s *Connection) sendReply(headers http.Header, stream *Stream, fin bool) error {
- var flags spdy.ControlFlags
- if fin {
- flags = spdy.ControlFlagFin
- }
-
- replyFrame := &spdy.SynReplyFrame{
- StreamId: stream.streamId,
- Headers: headers,
- CFHeader: spdy.ControlFrameHeader{Flags: flags},
- }
-
- return s.framer.WriteFrame(replyFrame)
-}
-
-func (s *Connection) sendResetFrame(status spdy.RstStreamStatus, streamId spdy.StreamId) error {
- resetFrame := &spdy.RstStreamFrame{
- StreamId: streamId,
- Status: status,
- }
-
- return s.framer.WriteFrame(resetFrame)
-}
-
-func (s *Connection) sendReset(status spdy.RstStreamStatus, stream *Stream) error {
- return s.sendResetFrame(status, stream.streamId)
-}
-
-func (s *Connection) sendStream(stream *Stream, fin bool) error {
- var flags spdy.ControlFlags
- if fin {
- flags = spdy.ControlFlagFin
- stream.finished = true
- }
-
- var parentId spdy.StreamId
- if stream.parent != nil {
- parentId = stream.parent.streamId
- }
-
- streamFrame := &spdy.SynStreamFrame{
- StreamId: spdy.StreamId(stream.streamId),
- AssociatedToStreamId: spdy.StreamId(parentId),
- Headers: stream.headers,
- CFHeader: spdy.ControlFrameHeader{Flags: flags},
- }
-
- return s.framer.WriteFrame(streamFrame)
-}
-
-// getNextStreamId returns the next sequential id
-// every call should produce a unique value or an error
-func (s *Connection) getNextStreamId() spdy.StreamId {
- sid := s.nextStreamId
- if sid > 0x7fffffff {
- return 0
- }
- s.nextStreamId = s.nextStreamId + 2
- return sid
-}
-
-// PeekNextStreamId returns the next sequential id and keeps the next id untouched
-func (s *Connection) PeekNextStreamId() spdy.StreamId {
- sid := s.nextStreamId
- return sid
-}
-
-func (s *Connection) validateStreamId(rid spdy.StreamId) error {
- if rid > 0x7fffffff || rid < s.receivedStreamId {
- return ErrInvalidStreamId
- }
- s.receivedStreamId = rid + 2
- return nil
-}
-
-func (s *Connection) addStream(stream *Stream) {
- s.streamCond.L.Lock()
- s.streams[stream.streamId] = stream
- debugMessage("(%p) (%p) Stream added, broadcasting: %d", s, stream, stream.streamId)
- s.streamCond.Broadcast()
- s.streamCond.L.Unlock()
-}
-
-func (s *Connection) removeStream(stream *Stream) {
- s.streamCond.L.Lock()
- delete(s.streams, stream.streamId)
- debugMessage("(%p) (%p) Stream removed, broadcasting: %d", s, stream, stream.streamId)
- s.streamCond.Broadcast()
- s.streamCond.L.Unlock()
-}
-
-func (s *Connection) getStream(streamId spdy.StreamId) (stream *Stream, ok bool) {
- s.streamLock.RLock()
- stream, ok = s.streams[streamId]
- s.streamLock.RUnlock()
- return
-}
-
-// FindStream looks up the given stream id and either waits for the
-// stream to be found or returns nil if the stream id is no longer
-// valid.
-func (s *Connection) FindStream(streamId uint32) *Stream {
- var stream *Stream
- var ok bool
- s.streamCond.L.Lock()
- stream, ok = s.streams[spdy.StreamId(streamId)]
- debugMessage("(%p) Found stream %d? %t", s, spdy.StreamId(streamId), ok)
- for !ok && streamId >= uint32(s.receivedStreamId) {
- s.streamCond.Wait()
- stream, ok = s.streams[spdy.StreamId(streamId)]
- }
- s.streamCond.L.Unlock()
- return stream
-}
-
-func (s *Connection) CloseChan() <-chan bool {
- return s.closeChan
-}
diff --git a/vendor/github.com/moby/spdystream/handlers.go b/vendor/github.com/moby/spdystream/handlers.go
deleted file mode 100644
index d68f61f812..0000000000
--- a/vendor/github.com/moby/spdystream/handlers.go
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package spdystream
-
-import (
- "io"
- "net/http"
-)
-
-// MirrorStreamHandler mirrors all streams.
-func MirrorStreamHandler(stream *Stream) {
- replyErr := stream.SendReply(http.Header{}, false)
- if replyErr != nil {
- return
- }
-
- go func() {
- io.Copy(stream, stream)
- stream.Close()
- }()
- go func() {
- for {
- header, receiveErr := stream.ReceiveHeader()
- if receiveErr != nil {
- return
- }
- sendErr := stream.SendHeader(header, false)
- if sendErr != nil {
- return
- }
- }
- }()
-}
-
-// NoopStreamHandler does nothing when stream connects.
-func NoOpStreamHandler(stream *Stream) {
- stream.SendReply(http.Header{}, false)
-}
diff --git a/vendor/github.com/moby/spdystream/priority.go b/vendor/github.com/moby/spdystream/priority.go
deleted file mode 100644
index d8eb3516ca..0000000000
--- a/vendor/github.com/moby/spdystream/priority.go
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package spdystream
-
-import (
- "container/heap"
- "sync"
-
- "github.com/moby/spdystream/spdy"
-)
-
-type prioritizedFrame struct {
- frame spdy.Frame
- priority uint8
- insertId uint64
-}
-
-type frameQueue []*prioritizedFrame
-
-func (fq frameQueue) Len() int {
- return len(fq)
-}
-
-func (fq frameQueue) Less(i, j int) bool {
- if fq[i].priority == fq[j].priority {
- return fq[i].insertId < fq[j].insertId
- }
- return fq[i].priority < fq[j].priority
-}
-
-func (fq frameQueue) Swap(i, j int) {
- fq[i], fq[j] = fq[j], fq[i]
-}
-
-func (fq *frameQueue) Push(x interface{}) {
- *fq = append(*fq, x.(*prioritizedFrame))
-}
-
-func (fq *frameQueue) Pop() interface{} {
- old := *fq
- n := len(old)
- *fq = old[0 : n-1]
- return old[n-1]
-}
-
-type PriorityFrameQueue struct {
- queue *frameQueue
- c *sync.Cond
- size int
- nextInsertId uint64
- drain bool
-}
-
-func NewPriorityFrameQueue(size int) *PriorityFrameQueue {
- queue := make(frameQueue, 0, size)
- heap.Init(&queue)
-
- return &PriorityFrameQueue{
- queue: &queue,
- size: size,
- c: sync.NewCond(&sync.Mutex{}),
- }
-}
-
-func (q *PriorityFrameQueue) Push(frame spdy.Frame, priority uint8) {
- q.c.L.Lock()
- defer q.c.L.Unlock()
- for q.queue.Len() >= q.size {
- q.c.Wait()
- }
- pFrame := &prioritizedFrame{
- frame: frame,
- priority: priority,
- insertId: q.nextInsertId,
- }
- q.nextInsertId = q.nextInsertId + 1
- heap.Push(q.queue, pFrame)
- q.c.Signal()
-}
-
-func (q *PriorityFrameQueue) Pop() spdy.Frame {
- q.c.L.Lock()
- defer q.c.L.Unlock()
- for q.queue.Len() == 0 {
- if q.drain {
- return nil
- }
- q.c.Wait()
- }
- frame := heap.Pop(q.queue).(*prioritizedFrame).frame
- q.c.Signal()
- return frame
-}
-
-func (q *PriorityFrameQueue) Drain() {
- q.c.L.Lock()
- defer q.c.L.Unlock()
- q.drain = true
- q.c.Broadcast()
-}
diff --git a/vendor/github.com/moby/spdystream/spdy/dictionary.go b/vendor/github.com/moby/spdystream/spdy/dictionary.go
deleted file mode 100644
index 392232f174..0000000000
--- a/vendor/github.com/moby/spdystream/spdy/dictionary.go
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package spdy
-
-// headerDictionary is the dictionary sent to the zlib compressor/decompressor.
-var headerDictionary = []byte{
- 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,
- 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,
- 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,
- 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,
- 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,
- 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,
- 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,
- 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,
- 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,
- 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
- 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,
- 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
- 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,
- 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,
- 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,
- 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,
- 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,
- 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,
- 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
- 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,
- 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,
- 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,
- 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,
- 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,
- 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,
- 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
- 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,
- 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
- 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
- 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,
- 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,
- 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,
- 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,
- 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
- 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,
- 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
- 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,
- 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
- 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,
- 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,
- 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,
- 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
- 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,
- 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,
- 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,
- 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,
- 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,
- 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,
- 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,
- 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,
- 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,
- 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,
- 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,
- 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,
- 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
- 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,
- 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,
- 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
- 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,
- 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,
- 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,
- 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,
- 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,
- 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,
- 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
- 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,
- 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,
- 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,
- 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,
- 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,
- 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,
- 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,
- 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
- 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,
- 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,
- 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,
- 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,
- 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,
- 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,
- 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,
- 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,
- 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,
- 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,
- 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,
- 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,
- 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
- 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,
- 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
- 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,
- 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
- 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,
- 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,
- 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,
- 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,
- 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,
- 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,
- 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,
- 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,
- 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,
- 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,
- 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,
- 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,
- 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,
- 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,
- 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,
- 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,
- 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,
- 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,
- 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,
- 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,
- 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,
- 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,
- 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,
- 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,
- 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,
- 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,
- 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,
- 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,
- 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,
- 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,
- 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,
- 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,
- 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,
- 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,
- 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,
- 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,
- 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,
- 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,
- 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,
- 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,
- 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,
- 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,
- 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,
- 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,
- 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,
- 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
- 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,
- 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,
- 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,
- 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,
- 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,
- 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,
- 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,
- 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,
- 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,
- 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,
- 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,
- 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,
- 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,
- 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,
- 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,
- 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,
- 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,
- 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,
- 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,
- 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,
- 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,
- 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,
- 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,
- 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,
- 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,
- 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,
- 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
- 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,
- 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,
- 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,
- 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
- 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,
- 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,
- 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,
- 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,
- 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e,
-}
diff --git a/vendor/github.com/moby/spdystream/spdy/read.go b/vendor/github.com/moby/spdystream/spdy/read.go
deleted file mode 100644
index 75ea045b8e..0000000000
--- a/vendor/github.com/moby/spdystream/spdy/read.go
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package spdy
-
-import (
- "compress/zlib"
- "encoding/binary"
- "io"
- "net/http"
- "strings"
-)
-
-func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) error {
- return f.readSynStreamFrame(h, frame)
-}
-
-func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) error {
- return f.readSynReplyFrame(h, frame)
-}
-
-func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
- return err
- }
- if frame.Status == 0 {
- return &Error{InvalidControlFrame, frame.StreamId}
- }
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- return nil
-}
-
-func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- var numSettings uint32
- if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil {
- return err
- }
- frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings)
- for i := uint32(0); i < numSettings; i++ {
- if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil {
- return err
- }
- frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24)
- frame.FlagIdValues[i].Id &= 0xffffff
- if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil {
- return err
- }
- }
- return nil
-}
-
-func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil {
- return err
- }
- if frame.Id == 0 {
- return &Error{ZeroStreamId, 0}
- }
- if frame.CFHeader.Flags != 0 {
- return &Error{InvalidControlFrame, StreamId(frame.Id)}
- }
- return nil
-}
-
-func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil {
- return err
- }
- if frame.CFHeader.Flags != 0 {
- return &Error{InvalidControlFrame, frame.LastGoodStreamId}
- }
- if frame.CFHeader.length != 8 {
- return &Error{InvalidControlFrame, frame.LastGoodStreamId}
- }
- if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
- return err
- }
- return nil
-}
-
-func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) error {
- return f.readHeadersFrame(h, frame)
-}
-
-func (frame *WindowUpdateFrame) read(h ControlFrameHeader, f *Framer) error {
- frame.CFHeader = h
- if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- if frame.CFHeader.Flags != 0 {
- return &Error{InvalidControlFrame, frame.StreamId}
- }
- if frame.CFHeader.length != 8 {
- return &Error{InvalidControlFrame, frame.StreamId}
- }
- if err := binary.Read(f.r, binary.BigEndian, &frame.DeltaWindowSize); err != nil {
- return err
- }
- return nil
-}
-
-func newControlFrame(frameType ControlFrameType) (controlFrame, error) {
- ctor, ok := cframeCtor[frameType]
- if !ok {
- return nil, &Error{Err: InvalidControlFrame}
- }
- return ctor(), nil
-}
-
-var cframeCtor = map[ControlFrameType]func() controlFrame{
- TypeSynStream: func() controlFrame { return new(SynStreamFrame) },
- TypeSynReply: func() controlFrame { return new(SynReplyFrame) },
- TypeRstStream: func() controlFrame { return new(RstStreamFrame) },
- TypeSettings: func() controlFrame { return new(SettingsFrame) },
- TypePing: func() controlFrame { return new(PingFrame) },
- TypeGoAway: func() controlFrame { return new(GoAwayFrame) },
- TypeHeaders: func() controlFrame { return new(HeadersFrame) },
- TypeWindowUpdate: func() controlFrame { return new(WindowUpdateFrame) },
-}
-
-func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) error {
- if f.headerDecompressor != nil {
- f.headerReader.N = payloadSize
- return nil
- }
- f.headerReader = io.LimitedReader{R: f.r, N: payloadSize}
- decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(headerDictionary))
- if err != nil {
- return err
- }
- f.headerDecompressor = decompressor
- return nil
-}
-
-// ReadFrame reads SPDY encoded data and returns a decompressed Frame.
-func (f *Framer) ReadFrame() (Frame, error) {
- var firstWord uint32
- if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil {
- return nil, err
- }
- if firstWord&0x80000000 != 0 {
- frameType := ControlFrameType(firstWord & 0xffff)
- version := uint16(firstWord >> 16 & 0x7fff)
- return f.parseControlFrame(version, frameType)
- }
- return f.parseDataFrame(StreamId(firstWord & 0x7fffffff))
-}
-
-func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, error) {
- var length uint32
- if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
- return nil, err
- }
- flags := ControlFlags((length & 0xff000000) >> 24)
- length &= 0xffffff
- header := ControlFrameHeader{version, frameType, flags, length}
- cframe, err := newControlFrame(frameType)
- if err != nil {
- return nil, err
- }
- if err = cframe.read(header, f); err != nil {
- return nil, err
- }
- return cframe, nil
-}
-
-func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) {
- var numHeaders uint32
- if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil {
- return nil, err
- }
- var e error
- h := make(http.Header, int(numHeaders))
- for i := 0; i < int(numHeaders); i++ {
- var length uint32
- if err := binary.Read(r, binary.BigEndian, &length); err != nil {
- return nil, err
- }
- nameBytes := make([]byte, length)
- if _, err := io.ReadFull(r, nameBytes); err != nil {
- return nil, err
- }
- name := string(nameBytes)
- if name != strings.ToLower(name) {
- e = &Error{UnlowercasedHeaderName, streamId}
- name = strings.ToLower(name)
- }
- if h[name] != nil {
- e = &Error{DuplicateHeaders, streamId}
- }
- if err := binary.Read(r, binary.BigEndian, &length); err != nil {
- return nil, err
- }
- value := make([]byte, length)
- if _, err := io.ReadFull(r, value); err != nil {
- return nil, err
- }
- valueList := strings.Split(string(value), headerValueSeparator)
- for _, v := range valueList {
- h.Add(name, v)
- }
- }
- if e != nil {
- return h, e
- }
- return h, nil
-}
-
-func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) error {
- frame.CFHeader = h
- var err error
- if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil {
- return err
- }
- if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil {
- return err
- }
- frame.Priority >>= 5
- if err = binary.Read(f.r, binary.BigEndian, &frame.Slot); err != nil {
- return err
- }
- reader := f.r
- if !f.headerCompressionDisabled {
- err := f.uncorkHeaderDecompressor(int64(h.length - 10))
- if err != nil {
- return err
- }
- reader = f.headerDecompressor
- }
- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
- if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
- err = &Error{WrongCompressedPayloadSize, 0}
- }
- if err != nil {
- return err
- }
- for h := range frame.Headers {
- if invalidReqHeaders[h] {
- return &Error{InvalidHeaderPresent, frame.StreamId}
- }
- }
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- return nil
-}
-
-func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) error {
- frame.CFHeader = h
- var err error
- if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- reader := f.r
- if !f.headerCompressionDisabled {
- err := f.uncorkHeaderDecompressor(int64(h.length - 4))
- if err != nil {
- return err
- }
- reader = f.headerDecompressor
- }
- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
- if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
- err = &Error{WrongCompressedPayloadSize, 0}
- }
- if err != nil {
- return err
- }
- for h := range frame.Headers {
- if invalidRespHeaders[h] {
- return &Error{InvalidHeaderPresent, frame.StreamId}
- }
- }
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- return nil
-}
-
-func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) error {
- frame.CFHeader = h
- var err error
- if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
- return err
- }
- reader := f.r
- if !f.headerCompressionDisabled {
- err := f.uncorkHeaderDecompressor(int64(h.length - 4))
- if err != nil {
- return err
- }
- reader = f.headerDecompressor
- }
- frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
- if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
- err = &Error{WrongCompressedPayloadSize, 0}
- }
- if err != nil {
- return err
- }
- var invalidHeaders map[string]bool
- if frame.StreamId%2 == 0 {
- invalidHeaders = invalidReqHeaders
- } else {
- invalidHeaders = invalidRespHeaders
- }
- for h := range frame.Headers {
- if invalidHeaders[h] {
- return &Error{InvalidHeaderPresent, frame.StreamId}
- }
- }
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- return nil
-}
-
-func (f *Framer) parseDataFrame(streamId StreamId) (*DataFrame, error) {
- var length uint32
- if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
- return nil, err
- }
- var frame DataFrame
- frame.StreamId = streamId
- frame.Flags = DataFlags(length >> 24)
- length &= 0xffffff
- frame.Data = make([]byte, length)
- if _, err := io.ReadFull(f.r, frame.Data); err != nil {
- return nil, err
- }
- if frame.StreamId == 0 {
- return nil, &Error{ZeroStreamId, 0}
- }
- return &frame, nil
-}
diff --git a/vendor/github.com/moby/spdystream/spdy/types.go b/vendor/github.com/moby/spdystream/spdy/types.go
deleted file mode 100644
index a254a43ab9..0000000000
--- a/vendor/github.com/moby/spdystream/spdy/types.go
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package spdy implements the SPDY protocol (currently SPDY/3), described in
-// http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3.
-package spdy
-
-import (
- "bytes"
- "compress/zlib"
- "io"
- "net/http"
-)
-
-// Version is the protocol version number that this package implements.
-const Version = 3
-
-// ControlFrameType stores the type field in a control frame header.
-type ControlFrameType uint16
-
-const (
- TypeSynStream ControlFrameType = 0x0001
- TypeSynReply ControlFrameType = 0x0002
- TypeRstStream ControlFrameType = 0x0003
- TypeSettings ControlFrameType = 0x0004
- TypePing ControlFrameType = 0x0006
- TypeGoAway ControlFrameType = 0x0007
- TypeHeaders ControlFrameType = 0x0008
- TypeWindowUpdate ControlFrameType = 0x0009
-)
-
-// ControlFlags are the flags that can be set on a control frame.
-type ControlFlags uint8
-
-const (
- ControlFlagFin ControlFlags = 0x01
- ControlFlagUnidirectional ControlFlags = 0x02
- ControlFlagSettingsClearSettings ControlFlags = 0x01
-)
-
-// DataFlags are the flags that can be set on a data frame.
-type DataFlags uint8
-
-const (
- DataFlagFin DataFlags = 0x01
-)
-
-// MaxDataLength is the maximum number of bytes that can be stored in one frame.
-const MaxDataLength = 1<<24 - 1
-
-// headerValueSepator separates multiple header values.
-const headerValueSeparator = "\x00"
-
-// Frame is a single SPDY frame in its unpacked in-memory representation. Use
-// Framer to read and write it.
-type Frame interface {
- write(f *Framer) error
-}
-
-// ControlFrameHeader contains all the fields in a control frame header,
-// in its unpacked in-memory representation.
-type ControlFrameHeader struct {
- // Note, high bit is the "Control" bit.
- version uint16 // spdy version number
- frameType ControlFrameType
- Flags ControlFlags
- length uint32 // length of data field
-}
-
-type controlFrame interface {
- Frame
- read(h ControlFrameHeader, f *Framer) error
-}
-
-// StreamId represents a 31-bit value identifying the stream.
-type StreamId uint32
-
-// SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM
-// frame.
-type SynStreamFrame struct {
- CFHeader ControlFrameHeader
- StreamId StreamId
- AssociatedToStreamId StreamId // stream id for a stream which this stream is associated to
- Priority uint8 // priority of this frame (3-bit)
- Slot uint8 // index in the server's credential vector of the client certificate
- Headers http.Header
-}
-
-// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame.
-type SynReplyFrame struct {
- CFHeader ControlFrameHeader
- StreamId StreamId
- Headers http.Header
-}
-
-// RstStreamStatus represents the status that led to a RST_STREAM.
-type RstStreamStatus uint32
-
-const (
- ProtocolError RstStreamStatus = iota + 1
- InvalidStream
- RefusedStream
- UnsupportedVersion
- Cancel
- InternalError
- FlowControlError
- StreamInUse
- StreamAlreadyClosed
- InvalidCredentials
- FrameTooLarge
-)
-
-// RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM
-// frame.
-type RstStreamFrame struct {
- CFHeader ControlFrameHeader
- StreamId StreamId
- Status RstStreamStatus
-}
-
-// SettingsFlag represents a flag in a SETTINGS frame.
-type SettingsFlag uint8
-
-const (
- FlagSettingsPersistValue SettingsFlag = 0x1
- FlagSettingsPersisted SettingsFlag = 0x2
-)
-
-// SettingsFlag represents the id of an id/value pair in a SETTINGS frame.
-type SettingsId uint32
-
-const (
- SettingsUploadBandwidth SettingsId = iota + 1
- SettingsDownloadBandwidth
- SettingsRoundTripTime
- SettingsMaxConcurrentStreams
- SettingsCurrentCwnd
- SettingsDownloadRetransRate
- SettingsInitialWindowSize
- SettingsClientCretificateVectorSize
-)
-
-// SettingsFlagIdValue is the unpacked, in-memory representation of the
-// combined flag/id/value for a setting in a SETTINGS frame.
-type SettingsFlagIdValue struct {
- Flag SettingsFlag
- Id SettingsId
- Value uint32
-}
-
-// SettingsFrame is the unpacked, in-memory representation of a SPDY
-// SETTINGS frame.
-type SettingsFrame struct {
- CFHeader ControlFrameHeader
- FlagIdValues []SettingsFlagIdValue
-}
-
-// PingFrame is the unpacked, in-memory representation of a PING frame.
-type PingFrame struct {
- CFHeader ControlFrameHeader
- Id uint32 // unique id for this ping, from server is even, from client is odd.
-}
-
-// GoAwayStatus represents the status in a GoAwayFrame.
-type GoAwayStatus uint32
-
-const (
- GoAwayOK GoAwayStatus = iota
- GoAwayProtocolError
- GoAwayInternalError
-)
-
-// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame.
-type GoAwayFrame struct {
- CFHeader ControlFrameHeader
- LastGoodStreamId StreamId // last stream id which was accepted by sender
- Status GoAwayStatus
-}
-
-// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame.
-type HeadersFrame struct {
- CFHeader ControlFrameHeader
- StreamId StreamId
- Headers http.Header
-}
-
-// WindowUpdateFrame is the unpacked, in-memory representation of a
-// WINDOW_UPDATE frame.
-type WindowUpdateFrame struct {
- CFHeader ControlFrameHeader
- StreamId StreamId
- DeltaWindowSize uint32 // additional number of bytes to existing window size
-}
-
-// TODO: Implement credential frame and related methods.
-
-// DataFrame is the unpacked, in-memory representation of a DATA frame.
-type DataFrame struct {
- // Note, high bit is the "Control" bit. Should be 0 for data frames.
- StreamId StreamId
- Flags DataFlags
- Data []byte // payload data of this frame
-}
-
-// A SPDY specific error.
-type ErrorCode string
-
-const (
- UnlowercasedHeaderName ErrorCode = "header was not lowercased"
- DuplicateHeaders ErrorCode = "multiple headers with same name"
- WrongCompressedPayloadSize ErrorCode = "compressed payload size was incorrect"
- UnknownFrameType ErrorCode = "unknown frame type"
- InvalidControlFrame ErrorCode = "invalid control frame"
- InvalidDataFrame ErrorCode = "invalid data frame"
- InvalidHeaderPresent ErrorCode = "frame contained invalid header"
- ZeroStreamId ErrorCode = "stream id zero is disallowed"
-)
-
-// Error contains both the type of error and additional values. StreamId is 0
-// if Error is not associated with a stream.
-type Error struct {
- Err ErrorCode
- StreamId StreamId
-}
-
-func (e *Error) Error() string {
- return string(e.Err)
-}
-
-var invalidReqHeaders = map[string]bool{
- "Connection": true,
- "Host": true,
- "Keep-Alive": true,
- "Proxy-Connection": true,
- "Transfer-Encoding": true,
-}
-
-var invalidRespHeaders = map[string]bool{
- "Connection": true,
- "Keep-Alive": true,
- "Proxy-Connection": true,
- "Transfer-Encoding": true,
-}
-
-// Framer handles serializing/deserializing SPDY frames, including compressing/
-// decompressing payloads.
-type Framer struct {
- headerCompressionDisabled bool
- w io.Writer
- headerBuf *bytes.Buffer
- headerCompressor *zlib.Writer
- r io.Reader
- headerReader io.LimitedReader
- headerDecompressor io.ReadCloser
-}
-
-// NewFramer allocates a new Framer for a given SPDY connection, represented by
-// a io.Writer and io.Reader. Note that Framer will read and write individual fields
-// from/to the Reader and Writer, so the caller should pass in an appropriately
-// buffered implementation to optimize performance.
-func NewFramer(w io.Writer, r io.Reader) (*Framer, error) {
- compressBuf := new(bytes.Buffer)
- compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary))
- if err != nil {
- return nil, err
- }
- framer := &Framer{
- w: w,
- headerBuf: compressBuf,
- headerCompressor: compressor,
- r: r,
- }
- return framer, nil
-}
diff --git a/vendor/github.com/moby/spdystream/spdy/write.go b/vendor/github.com/moby/spdystream/spdy/write.go
deleted file mode 100644
index ab6d91f3b8..0000000000
--- a/vendor/github.com/moby/spdystream/spdy/write.go
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package spdy
-
-import (
- "encoding/binary"
- "io"
- "net/http"
- "strings"
-)
-
-func (frame *SynStreamFrame) write(f *Framer) error {
- return f.writeSynStreamFrame(frame)
-}
-
-func (frame *SynReplyFrame) write(f *Framer) error {
- return f.writeSynReplyFrame(frame)
-}
-
-func (frame *RstStreamFrame) write(f *Framer) (err error) {
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeRstStream
- frame.CFHeader.Flags = 0
- frame.CFHeader.length = 8
-
- // Serialize frame to Writer.
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- if frame.Status == 0 {
- return &Error{InvalidControlFrame, frame.StreamId}
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
- return
- }
- return
-}
-
-func (frame *SettingsFrame) write(f *Framer) (err error) {
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeSettings
- frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
-
- // Serialize frame to Writer.
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
- return
- }
- for _, flagIdValue := range frame.FlagIdValues {
- flagId := uint32(flagIdValue.Flag)<<24 | uint32(flagIdValue.Id)
- if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
- return
- }
- }
- return
-}
-
-func (frame *PingFrame) write(f *Framer) (err error) {
- if frame.Id == 0 {
- return &Error{ZeroStreamId, 0}
- }
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypePing
- frame.CFHeader.Flags = 0
- frame.CFHeader.length = 4
-
- // Serialize frame to Writer.
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
- return
- }
- return
-}
-
-func (frame *GoAwayFrame) write(f *Framer) (err error) {
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeGoAway
- frame.CFHeader.Flags = 0
- frame.CFHeader.length = 8
-
- // Serialize frame to Writer.
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
- return
- }
- return nil
-}
-
-func (frame *HeadersFrame) write(f *Framer) error {
- return f.writeHeadersFrame(frame)
-}
-
-func (frame *WindowUpdateFrame) write(f *Framer) (err error) {
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeWindowUpdate
- frame.CFHeader.Flags = 0
- frame.CFHeader.length = 8
-
- // Serialize frame to Writer.
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.DeltaWindowSize); err != nil {
- return
- }
- return nil
-}
-
-func (frame *DataFrame) write(f *Framer) error {
- return f.writeDataFrame(frame)
-}
-
-// WriteFrame writes a frame.
-func (f *Framer) WriteFrame(frame Frame) error {
- return frame.write(f)
-}
-
-func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error {
- if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
- return err
- }
- if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
- return err
- }
- flagsAndLength := uint32(h.Flags)<<24 | h.length
- if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
- return err
- }
- return nil
-}
-
-func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) {
- n = 0
- if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil {
- return
- }
- n += 2
- for name, values := range h {
- if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil {
- return
- }
- n += 2
- name = strings.ToLower(name)
- if _, err = io.WriteString(w, name); err != nil {
- return
- }
- n += len(name)
- v := strings.Join(values, headerValueSeparator)
- if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil {
- return
- }
- n += 2
- if _, err = io.WriteString(w, v); err != nil {
- return
- }
- n += len(v)
- }
- return
-}
-
-func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) {
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- // Marshal the headers.
- var writer io.Writer = f.headerBuf
- if !f.headerCompressionDisabled {
- writer = f.headerCompressor
- }
- if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
- return
- }
- if !f.headerCompressionDisabled {
- f.headerCompressor.Flush()
- }
-
- // Set ControlFrameHeader.
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeSynStream
- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
-
- // Serialize frame to Writer.
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return err
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return err
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
- return err
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<5); err != nil {
- return err
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.Slot); err != nil {
- return err
- }
- if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
- return err
- }
- f.headerBuf.Reset()
- return nil
-}
-
-func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) {
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- // Marshal the headers.
- var writer io.Writer = f.headerBuf
- if !f.headerCompressionDisabled {
- writer = f.headerCompressor
- }
- if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
- return
- }
- if !f.headerCompressionDisabled {
- f.headerCompressor.Flush()
- }
-
- // Set ControlFrameHeader.
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeSynReply
- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
-
- // Serialize frame to Writer.
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
- return
- }
- f.headerBuf.Reset()
- return
-}
-
-func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) {
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- // Marshal the headers.
- var writer io.Writer = f.headerBuf
- if !f.headerCompressionDisabled {
- writer = f.headerCompressor
- }
- if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
- return
- }
- if !f.headerCompressionDisabled {
- f.headerCompressor.Flush()
- }
-
- // Set ControlFrameHeader.
- frame.CFHeader.version = Version
- frame.CFHeader.frameType = TypeHeaders
- frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
-
- // Serialize frame to Writer.
- if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
- return
- }
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
- return
- }
- f.headerBuf.Reset()
- return
-}
-
-func (f *Framer) writeDataFrame(frame *DataFrame) (err error) {
- if frame.StreamId == 0 {
- return &Error{ZeroStreamId, 0}
- }
- if frame.StreamId&0x80000000 != 0 || len(frame.Data) > MaxDataLength {
- return &Error{InvalidDataFrame, frame.StreamId}
- }
-
- // Serialize frame to Writer.
- if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
- return
- }
- flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data))
- if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
- return
- }
- if _, err = f.w.Write(frame.Data); err != nil {
- return
- }
- return nil
-}
diff --git a/vendor/github.com/moby/spdystream/stream.go b/vendor/github.com/moby/spdystream/stream.go
deleted file mode 100644
index 404e3c02df..0000000000
--- a/vendor/github.com/moby/spdystream/stream.go
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package spdystream
-
-import (
- "errors"
- "fmt"
- "io"
- "net"
- "net/http"
- "sync"
- "time"
-
- "github.com/moby/spdystream/spdy"
-)
-
-var (
- ErrUnreadPartialData = errors.New("unread partial data")
-)
-
-type Stream struct {
- streamId spdy.StreamId
- parent *Stream
- conn *Connection
- startChan chan error
-
- dataLock sync.RWMutex
- dataChan chan []byte
- unread []byte
-
- priority uint8
- headers http.Header
- headerChan chan http.Header
- finishLock sync.Mutex
- finished bool
- replyCond *sync.Cond
- replied bool
- closeLock sync.Mutex
- closeChan chan bool
-}
-
-// WriteData writes data to stream, sending a dataframe per call
-func (s *Stream) WriteData(data []byte, fin bool) error {
- s.waitWriteReply()
- var flags spdy.DataFlags
-
- if fin {
- flags = spdy.DataFlagFin
- s.finishLock.Lock()
- if s.finished {
- s.finishLock.Unlock()
- return ErrWriteClosedStream
- }
- s.finished = true
- s.finishLock.Unlock()
- }
-
- dataFrame := &spdy.DataFrame{
- StreamId: s.streamId,
- Flags: flags,
- Data: data,
- }
-
- debugMessage("(%p) (%d) Writing data frame", s, s.streamId)
- return s.conn.framer.WriteFrame(dataFrame)
-}
-
-// Write writes bytes to a stream, calling write data for each call.
-func (s *Stream) Write(data []byte) (n int, err error) {
- err = s.WriteData(data, false)
- if err == nil {
- n = len(data)
- }
- return
-}
-
-// Read reads bytes from a stream, a single read will never get more
-// than what is sent on a single data frame, but a multiple calls to
-// read may get data from the same data frame.
-func (s *Stream) Read(p []byte) (n int, err error) {
- if s.unread == nil {
- select {
- case <-s.closeChan:
- return 0, io.EOF
- case read, ok := <-s.dataChan:
- if !ok {
- return 0, io.EOF
- }
- s.unread = read
- }
- }
- n = copy(p, s.unread)
- if n < len(s.unread) {
- s.unread = s.unread[n:]
- } else {
- s.unread = nil
- }
- return
-}
-
-// ReadData reads an entire data frame and returns the byte array
-// from the data frame. If there is unread data from the result
-// of a Read call, this function will return an ErrUnreadPartialData.
-func (s *Stream) ReadData() ([]byte, error) {
- debugMessage("(%p) Reading data from %d", s, s.streamId)
- if s.unread != nil {
- return nil, ErrUnreadPartialData
- }
- select {
- case <-s.closeChan:
- return nil, io.EOF
- case read, ok := <-s.dataChan:
- if !ok {
- return nil, io.EOF
- }
- return read, nil
- }
-}
-
-func (s *Stream) waitWriteReply() {
- if s.replyCond != nil {
- s.replyCond.L.Lock()
- for !s.replied {
- s.replyCond.Wait()
- }
- s.replyCond.L.Unlock()
- }
-}
-
-// Wait waits for the stream to receive a reply.
-func (s *Stream) Wait() error {
- return s.WaitTimeout(time.Duration(0))
-}
-
-// WaitTimeout waits for the stream to receive a reply or for timeout.
-// When the timeout is reached, ErrTimeout will be returned.
-func (s *Stream) WaitTimeout(timeout time.Duration) error {
- var timeoutChan <-chan time.Time
- if timeout > time.Duration(0) {
- timeoutChan = time.After(timeout)
- }
-
- select {
- case err := <-s.startChan:
- if err != nil {
- return err
- }
- break
- case <-timeoutChan:
- return ErrTimeout
- }
- return nil
-}
-
-// Close closes the stream by sending an empty data frame with the
-// finish flag set, indicating this side is finished with the stream.
-func (s *Stream) Close() error {
- select {
- case <-s.closeChan:
- // Stream is now fully closed
- s.conn.removeStream(s)
- default:
- break
- }
- return s.WriteData([]byte{}, true)
-}
-
-// Reset sends a reset frame, putting the stream into the fully closed state.
-func (s *Stream) Reset() error {
- s.conn.removeStream(s)
- return s.resetStream()
-}
-
-func (s *Stream) resetStream() error {
- // Always call closeRemoteChannels, even if s.finished is already true.
- // This makes it so that stream.Close() followed by stream.Reset() allows
- // stream.Read() to unblock.
- s.closeRemoteChannels()
-
- s.finishLock.Lock()
- if s.finished {
- s.finishLock.Unlock()
- return nil
- }
- s.finished = true
- s.finishLock.Unlock()
-
- resetFrame := &spdy.RstStreamFrame{
- StreamId: s.streamId,
- Status: spdy.Cancel,
- }
- return s.conn.framer.WriteFrame(resetFrame)
-}
-
-// CreateSubStream creates a stream using the current as the parent
-func (s *Stream) CreateSubStream(headers http.Header, fin bool) (*Stream, error) {
- return s.conn.CreateStream(headers, s, fin)
-}
-
-// SetPriority sets the stream priority, does not affect the
-// remote priority of this stream after Open has been called.
-// Valid values are 0 through 7, 0 being the highest priority
-// and 7 the lowest.
-func (s *Stream) SetPriority(priority uint8) {
- s.priority = priority
-}
-
-// SendHeader sends a header frame across the stream
-func (s *Stream) SendHeader(headers http.Header, fin bool) error {
- return s.conn.sendHeaders(headers, s, fin)
-}
-
-// SendReply sends a reply on a stream, only valid to be called once
-// when handling a new stream
-func (s *Stream) SendReply(headers http.Header, fin bool) error {
- if s.replyCond == nil {
- return errors.New("cannot reply on initiated stream")
- }
- s.replyCond.L.Lock()
- defer s.replyCond.L.Unlock()
- if s.replied {
- return nil
- }
-
- err := s.conn.sendReply(headers, s, fin)
- if err != nil {
- return err
- }
-
- s.replied = true
- s.replyCond.Broadcast()
- return nil
-}
-
-// Refuse sends a reset frame with the status refuse, only
-// valid to be called once when handling a new stream. This
-// may be used to indicate that a stream is not allowed
-// when http status codes are not being used.
-func (s *Stream) Refuse() error {
- if s.replied {
- return nil
- }
- s.replied = true
- return s.conn.sendReset(spdy.RefusedStream, s)
-}
-
-// Cancel sends a reset frame with the status canceled. This
-// can be used at any time by the creator of the Stream to
-// indicate the stream is no longer needed.
-func (s *Stream) Cancel() error {
- return s.conn.sendReset(spdy.Cancel, s)
-}
-
-// ReceiveHeader receives a header sent on the other side
-// of the stream. This function will block until a header
-// is received or stream is closed.
-func (s *Stream) ReceiveHeader() (http.Header, error) {
- select {
- case <-s.closeChan:
- break
- case header, ok := <-s.headerChan:
- if !ok {
- return nil, fmt.Errorf("header chan closed")
- }
- return header, nil
- }
- return nil, fmt.Errorf("stream closed")
-}
-
-// Parent returns the parent stream
-func (s *Stream) Parent() *Stream {
- return s.parent
-}
-
-// Headers returns the headers used to create the stream
-func (s *Stream) Headers() http.Header {
- return s.headers
-}
-
-// String returns the string version of stream using the
-// streamId to uniquely identify the stream
-func (s *Stream) String() string {
- return fmt.Sprintf("stream:%d", s.streamId)
-}
-
-// Identifier returns a 32 bit identifier for the stream
-func (s *Stream) Identifier() uint32 {
- return uint32(s.streamId)
-}
-
-// IsFinished returns whether the stream has finished
-// sending data
-func (s *Stream) IsFinished() bool {
- return s.finished
-}
-
-// Implement net.Conn interface
-
-func (s *Stream) LocalAddr() net.Addr {
- return s.conn.conn.LocalAddr()
-}
-
-func (s *Stream) RemoteAddr() net.Addr {
- return s.conn.conn.RemoteAddr()
-}
-
-// TODO set per stream values instead of connection-wide
-
-func (s *Stream) SetDeadline(t time.Time) error {
- return s.conn.conn.SetDeadline(t)
-}
-
-func (s *Stream) SetReadDeadline(t time.Time) error {
- return s.conn.conn.SetReadDeadline(t)
-}
-
-func (s *Stream) SetWriteDeadline(t time.Time) error {
- return s.conn.conn.SetWriteDeadline(t)
-}
-
-func (s *Stream) closeRemoteChannels() {
- s.closeLock.Lock()
- defer s.closeLock.Unlock()
- select {
- case <-s.closeChan:
- default:
- close(s.closeChan)
- }
-}
diff --git a/vendor/github.com/moby/spdystream/utils.go b/vendor/github.com/moby/spdystream/utils.go
deleted file mode 100644
index e9f7fffd60..0000000000
--- a/vendor/github.com/moby/spdystream/utils.go
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- Copyright 2014-2021 Docker Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package spdystream
-
-import (
- "log"
- "os"
-)
-
-var (
- DEBUG = os.Getenv("DEBUG")
-)
-
-func debugMessage(fmt string, args ...interface{}) {
- if DEBUG != "" {
- log.Printf(fmt, args...)
- }
-}
diff --git a/vendor/github.com/mxk/go-flowrate/LICENSE b/vendor/github.com/mxk/go-flowrate/LICENSE
deleted file mode 100644
index e9f9f628ba..0000000000
--- a/vendor/github.com/mxk/go-flowrate/LICENSE
+++ /dev/null
@@ -1,29 +0,0 @@
-Copyright (c) 2014 The Go-FlowRate Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the
- distribution.
-
- * Neither the name of the go-flowrate project nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/mxk/go-flowrate/flowrate/flowrate.go b/vendor/github.com/mxk/go-flowrate/flowrate/flowrate.go
deleted file mode 100644
index 1b727721e1..0000000000
--- a/vendor/github.com/mxk/go-flowrate/flowrate/flowrate.go
+++ /dev/null
@@ -1,267 +0,0 @@
-//
-// Written by Maxim Khitrov (November 2012)
-//
-
-// Package flowrate provides the tools for monitoring and limiting the flow rate
-// of an arbitrary data stream.
-package flowrate
-
-import (
- "math"
- "sync"
- "time"
-)
-
-// Monitor monitors and limits the transfer rate of a data stream.
-type Monitor struct {
- mu sync.Mutex // Mutex guarding access to all internal fields
- active bool // Flag indicating an active transfer
- start time.Duration // Transfer start time (clock() value)
- bytes int64 // Total number of bytes transferred
- samples int64 // Total number of samples taken
-
- rSample float64 // Most recent transfer rate sample (bytes per second)
- rEMA float64 // Exponential moving average of rSample
- rPeak float64 // Peak transfer rate (max of all rSamples)
- rWindow float64 // rEMA window (seconds)
-
- sBytes int64 // Number of bytes transferred since sLast
- sLast time.Duration // Most recent sample time (stop time when inactive)
- sRate time.Duration // Sampling rate
-
- tBytes int64 // Number of bytes expected in the current transfer
- tLast time.Duration // Time of the most recent transfer of at least 1 byte
-}
-
-// New creates a new flow control monitor. Instantaneous transfer rate is
-// measured and updated for each sampleRate interval. windowSize determines the
-// weight of each sample in the exponential moving average (EMA) calculation.
-// The exact formulas are:
-//
-// sampleTime = currentTime - prevSampleTime
-// sampleRate = byteCount / sampleTime
-// weight = 1 - exp(-sampleTime/windowSize)
-// newRate = weight*sampleRate + (1-weight)*oldRate
-//
-// The default values for sampleRate and windowSize (if <= 0) are 100ms and 1s,
-// respectively.
-func New(sampleRate, windowSize time.Duration) *Monitor {
- if sampleRate = clockRound(sampleRate); sampleRate <= 0 {
- sampleRate = 5 * clockRate
- }
- if windowSize <= 0 {
- windowSize = 1 * time.Second
- }
- now := clock()
- return &Monitor{
- active: true,
- start: now,
- rWindow: windowSize.Seconds(),
- sLast: now,
- sRate: sampleRate,
- tLast: now,
- }
-}
-
-// Update records the transfer of n bytes and returns n. It should be called
-// after each Read/Write operation, even if n is 0.
-func (m *Monitor) Update(n int) int {
- m.mu.Lock()
- m.update(n)
- m.mu.Unlock()
- return n
-}
-
-// IO is a convenience method intended to wrap io.Reader and io.Writer method
-// execution. It calls m.Update(n) and then returns (n, err) unmodified.
-func (m *Monitor) IO(n int, err error) (int, error) {
- return m.Update(n), err
-}
-
-// Done marks the transfer as finished and prevents any further updates or
-// limiting. Instantaneous and current transfer rates drop to 0. Update, IO, and
-// Limit methods become NOOPs. It returns the total number of bytes transferred.
-func (m *Monitor) Done() int64 {
- m.mu.Lock()
- if now := m.update(0); m.sBytes > 0 {
- m.reset(now)
- }
- m.active = false
- m.tLast = 0
- n := m.bytes
- m.mu.Unlock()
- return n
-}
-
-// timeRemLimit is the maximum Status.TimeRem value.
-const timeRemLimit = 999*time.Hour + 59*time.Minute + 59*time.Second
-
-// Status represents the current Monitor status. All transfer rates are in bytes
-// per second rounded to the nearest byte.
-type Status struct {
- Active bool // Flag indicating an active transfer
- Start time.Time // Transfer start time
- Duration time.Duration // Time period covered by the statistics
- Idle time.Duration // Time since the last transfer of at least 1 byte
- Bytes int64 // Total number of bytes transferred
- Samples int64 // Total number of samples taken
- InstRate int64 // Instantaneous transfer rate
- CurRate int64 // Current transfer rate (EMA of InstRate)
- AvgRate int64 // Average transfer rate (Bytes / Duration)
- PeakRate int64 // Maximum instantaneous transfer rate
- BytesRem int64 // Number of bytes remaining in the transfer
- TimeRem time.Duration // Estimated time to completion
- Progress Percent // Overall transfer progress
-}
-
-// Status returns current transfer status information. The returned value
-// becomes static after a call to Done.
-func (m *Monitor) Status() Status {
- m.mu.Lock()
- now := m.update(0)
- s := Status{
- Active: m.active,
- Start: clockToTime(m.start),
- Duration: m.sLast - m.start,
- Idle: now - m.tLast,
- Bytes: m.bytes,
- Samples: m.samples,
- PeakRate: round(m.rPeak),
- BytesRem: m.tBytes - m.bytes,
- Progress: percentOf(float64(m.bytes), float64(m.tBytes)),
- }
- if s.BytesRem < 0 {
- s.BytesRem = 0
- }
- if s.Duration > 0 {
- rAvg := float64(s.Bytes) / s.Duration.Seconds()
- s.AvgRate = round(rAvg)
- if s.Active {
- s.InstRate = round(m.rSample)
- s.CurRate = round(m.rEMA)
- if s.BytesRem > 0 {
- if tRate := 0.8*m.rEMA + 0.2*rAvg; tRate > 0 {
- ns := float64(s.BytesRem) / tRate * 1e9
- if ns > float64(timeRemLimit) {
- ns = float64(timeRemLimit)
- }
- s.TimeRem = clockRound(time.Duration(ns))
- }
- }
- }
- }
- m.mu.Unlock()
- return s
-}
-
-// Limit restricts the instantaneous (per-sample) data flow to rate bytes per
-// second. It returns the maximum number of bytes (0 <= n <= want) that may be
-// transferred immediately without exceeding the limit. If block == true, the
-// call blocks until n > 0. want is returned unmodified if want < 1, rate < 1,
-// or the transfer is inactive (after a call to Done).
-//
-// At least one byte is always allowed to be transferred in any given sampling
-// period. Thus, if the sampling rate is 100ms, the lowest achievable flow rate
-// is 10 bytes per second.
-//
-// For usage examples, see the implementation of Reader and Writer in io.go.
-func (m *Monitor) Limit(want int, rate int64, block bool) (n int) {
- if want < 1 || rate < 1 {
- return want
- }
- m.mu.Lock()
-
- // Determine the maximum number of bytes that can be sent in one sample
- limit := round(float64(rate) * m.sRate.Seconds())
- if limit <= 0 {
- limit = 1
- }
-
- // If block == true, wait until m.sBytes < limit
- if now := m.update(0); block {
- for m.sBytes >= limit && m.active {
- now = m.waitNextSample(now)
- }
- }
-
- // Make limit <= want (unlimited if the transfer is no longer active)
- if limit -= m.sBytes; limit > int64(want) || !m.active {
- limit = int64(want)
- }
- m.mu.Unlock()
-
- if limit < 0 {
- limit = 0
- }
- return int(limit)
-}
-
-// SetTransferSize specifies the total size of the data transfer, which allows
-// the Monitor to calculate the overall progress and time to completion.
-func (m *Monitor) SetTransferSize(bytes int64) {
- if bytes < 0 {
- bytes = 0
- }
- m.mu.Lock()
- m.tBytes = bytes
- m.mu.Unlock()
-}
-
-// update accumulates the transferred byte count for the current sample until
-// clock() - m.sLast >= m.sRate. The monitor status is updated once the current
-// sample is done.
-func (m *Monitor) update(n int) (now time.Duration) {
- if !m.active {
- return
- }
- if now = clock(); n > 0 {
- m.tLast = now
- }
- m.sBytes += int64(n)
- if sTime := now - m.sLast; sTime >= m.sRate {
- t := sTime.Seconds()
- if m.rSample = float64(m.sBytes) / t; m.rSample > m.rPeak {
- m.rPeak = m.rSample
- }
-
- // Exponential moving average using a method similar to *nix load
- // average calculation. Longer sampling periods carry greater weight.
- if m.samples > 0 {
- w := math.Exp(-t / m.rWindow)
- m.rEMA = m.rSample + w*(m.rEMA-m.rSample)
- } else {
- m.rEMA = m.rSample
- }
- m.reset(now)
- }
- return
-}
-
-// reset clears the current sample state in preparation for the next sample.
-func (m *Monitor) reset(sampleTime time.Duration) {
- m.bytes += m.sBytes
- m.samples++
- m.sBytes = 0
- m.sLast = sampleTime
-}
-
-// waitNextSample sleeps for the remainder of the current sample. The lock is
-// released and reacquired during the actual sleep period, so it's possible for
-// the transfer to be inactive when this method returns.
-func (m *Monitor) waitNextSample(now time.Duration) time.Duration {
- const minWait = 5 * time.Millisecond
- current := m.sLast
-
- // sleep until the last sample time changes (ideally, just one iteration)
- for m.sLast == current && m.active {
- d := current + m.sRate - now
- m.mu.Unlock()
- if d < minWait {
- d = minWait
- }
- time.Sleep(d)
- m.mu.Lock()
- now = m.update(0)
- }
- return now
-}
diff --git a/vendor/github.com/mxk/go-flowrate/flowrate/io.go b/vendor/github.com/mxk/go-flowrate/flowrate/io.go
deleted file mode 100644
index fbe0909725..0000000000
--- a/vendor/github.com/mxk/go-flowrate/flowrate/io.go
+++ /dev/null
@@ -1,133 +0,0 @@
-//
-// Written by Maxim Khitrov (November 2012)
-//
-
-package flowrate
-
-import (
- "errors"
- "io"
-)
-
-// ErrLimit is returned by the Writer when a non-blocking write is short due to
-// the transfer rate limit.
-var ErrLimit = errors.New("flowrate: flow rate limit exceeded")
-
-// Limiter is implemented by the Reader and Writer to provide a consistent
-// interface for monitoring and controlling data transfer.
-type Limiter interface {
- Done() int64
- Status() Status
- SetTransferSize(bytes int64)
- SetLimit(new int64) (old int64)
- SetBlocking(new bool) (old bool)
-}
-
-// Reader implements io.ReadCloser with a restriction on the rate of data
-// transfer.
-type Reader struct {
- io.Reader // Data source
- *Monitor // Flow control monitor
-
- limit int64 // Rate limit in bytes per second (unlimited when <= 0)
- block bool // What to do when no new bytes can be read due to the limit
-}
-
-// NewReader restricts all Read operations on r to limit bytes per second.
-func NewReader(r io.Reader, limit int64) *Reader {
- return &Reader{r, New(0, 0), limit, true}
-}
-
-// Read reads up to len(p) bytes into p without exceeding the current transfer
-// rate limit. It returns (0, nil) immediately if r is non-blocking and no new
-// bytes can be read at this time.
-func (r *Reader) Read(p []byte) (n int, err error) {
- p = p[:r.Limit(len(p), r.limit, r.block)]
- if len(p) > 0 {
- n, err = r.IO(r.Reader.Read(p))
- }
- return
-}
-
-// SetLimit changes the transfer rate limit to new bytes per second and returns
-// the previous setting.
-func (r *Reader) SetLimit(new int64) (old int64) {
- old, r.limit = r.limit, new
- return
-}
-
-// SetBlocking changes the blocking behavior and returns the previous setting. A
-// Read call on a non-blocking reader returns immediately if no additional bytes
-// may be read at this time due to the rate limit.
-func (r *Reader) SetBlocking(new bool) (old bool) {
- old, r.block = r.block, new
- return
-}
-
-// Close closes the underlying reader if it implements the io.Closer interface.
-func (r *Reader) Close() error {
- defer r.Done()
- if c, ok := r.Reader.(io.Closer); ok {
- return c.Close()
- }
- return nil
-}
-
-// Writer implements io.WriteCloser with a restriction on the rate of data
-// transfer.
-type Writer struct {
- io.Writer // Data destination
- *Monitor // Flow control monitor
-
- limit int64 // Rate limit in bytes per second (unlimited when <= 0)
- block bool // What to do when no new bytes can be written due to the limit
-}
-
-// NewWriter restricts all Write operations on w to limit bytes per second. The
-// transfer rate and the default blocking behavior (true) can be changed
-// directly on the returned *Writer.
-func NewWriter(w io.Writer, limit int64) *Writer {
- return &Writer{w, New(0, 0), limit, true}
-}
-
-// Write writes len(p) bytes from p to the underlying data stream without
-// exceeding the current transfer rate limit. It returns (n, ErrLimit) if w is
-// non-blocking and no additional bytes can be written at this time.
-func (w *Writer) Write(p []byte) (n int, err error) {
- var c int
- for len(p) > 0 && err == nil {
- s := p[:w.Limit(len(p), w.limit, w.block)]
- if len(s) > 0 {
- c, err = w.IO(w.Writer.Write(s))
- } else {
- return n, ErrLimit
- }
- p = p[c:]
- n += c
- }
- return
-}
-
-// SetLimit changes the transfer rate limit to new bytes per second and returns
-// the previous setting.
-func (w *Writer) SetLimit(new int64) (old int64) {
- old, w.limit = w.limit, new
- return
-}
-
-// SetBlocking changes the blocking behavior and returns the previous setting. A
-// Write call on a non-blocking writer returns as soon as no additional bytes
-// may be written at this time due to the rate limit.
-func (w *Writer) SetBlocking(new bool) (old bool) {
- old, w.block = w.block, new
- return
-}
-
-// Close closes the underlying writer if it implements the io.Closer interface.
-func (w *Writer) Close() error {
- defer w.Done()
- if c, ok := w.Writer.(io.Closer); ok {
- return c.Close()
- }
- return nil
-}
diff --git a/vendor/github.com/mxk/go-flowrate/flowrate/util.go b/vendor/github.com/mxk/go-flowrate/flowrate/util.go
deleted file mode 100644
index 4caac583fc..0000000000
--- a/vendor/github.com/mxk/go-flowrate/flowrate/util.go
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// Written by Maxim Khitrov (November 2012)
-//
-
-package flowrate
-
-import (
- "math"
- "strconv"
- "time"
-)
-
-// clockRate is the resolution and precision of clock().
-const clockRate = 20 * time.Millisecond
-
-// czero is the process start time rounded down to the nearest clockRate
-// increment.
-var czero = time.Duration(time.Now().UnixNano()) / clockRate * clockRate
-
-// clock returns a low resolution timestamp relative to the process start time.
-func clock() time.Duration {
- return time.Duration(time.Now().UnixNano())/clockRate*clockRate - czero
-}
-
-// clockToTime converts a clock() timestamp to an absolute time.Time value.
-func clockToTime(c time.Duration) time.Time {
- return time.Unix(0, int64(czero+c))
-}
-
-// clockRound returns d rounded to the nearest clockRate increment.
-func clockRound(d time.Duration) time.Duration {
- return (d + clockRate>>1) / clockRate * clockRate
-}
-
-// round returns x rounded to the nearest int64 (non-negative values only).
-func round(x float64) int64 {
- if _, frac := math.Modf(x); frac >= 0.5 {
- return int64(math.Ceil(x))
- }
- return int64(math.Floor(x))
-}
-
-// Percent represents a percentage in increments of 1/1000th of a percent.
-type Percent uint32
-
-// percentOf calculates what percent of the total is x.
-func percentOf(x, total float64) Percent {
- if x < 0 || total <= 0 {
- return 0
- } else if p := round(x / total * 1e5); p <= math.MaxUint32 {
- return Percent(p)
- }
- return Percent(math.MaxUint32)
-}
-
-func (p Percent) Float() float64 {
- return float64(p) * 1e-3
-}
-
-func (p Percent) String() string {
- var buf [12]byte
- b := strconv.AppendUint(buf[:0], uint64(p)/1000, 10)
- n := len(b)
- b = strconv.AppendUint(b, 1000+uint64(p)%1000, 10)
- b[n] = '.'
- return string(append(b, '%'))
-}
diff --git a/vendor/golang.org/x/net/html/atom/atom.go b/vendor/golang.org/x/net/html/atom/atom.go
deleted file mode 100644
index cd0a8ac154..0000000000
--- a/vendor/golang.org/x/net/html/atom/atom.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package atom provides integer codes (also known as atoms) for a fixed set of
-// frequently occurring HTML strings: tag names and attribute keys such as "p"
-// and "id".
-//
-// Sharing an atom's name between all elements with the same tag can result in
-// fewer string allocations when tokenizing and parsing HTML. Integer
-// comparisons are also generally faster than string comparisons.
-//
-// The value of an atom's particular code is not guaranteed to stay the same
-// between versions of this package. Neither is any ordering guaranteed:
-// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to
-// be dense. The only guarantees are that e.g. looking up "div" will yield
-// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0.
-package atom // import "golang.org/x/net/html/atom"
-
-// Atom is an integer code for a string. The zero value maps to "".
-type Atom uint32
-
-// String returns the atom's name.
-func (a Atom) String() string {
- start := uint32(a >> 8)
- n := uint32(a & 0xff)
- if start+n > uint32(len(atomText)) {
- return ""
- }
- return atomText[start : start+n]
-}
-
-func (a Atom) string() string {
- return atomText[a>>8 : a>>8+a&0xff]
-}
-
-// fnv computes the FNV hash with an arbitrary starting value h.
-func fnv(h uint32, s []byte) uint32 {
- for i := range s {
- h ^= uint32(s[i])
- h *= 16777619
- }
- return h
-}
-
-func match(s string, t []byte) bool {
- for i, c := range t {
- if s[i] != c {
- return false
- }
- }
- return true
-}
-
-// Lookup returns the atom whose name is s. It returns zero if there is no
-// such atom. The lookup is case sensitive.
-func Lookup(s []byte) Atom {
- if len(s) == 0 || len(s) > maxAtomLen {
- return 0
- }
- h := fnv(hash0, s)
- if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
- return a
- }
- if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
- return a
- }
- return 0
-}
-
-// String returns a string whose contents are equal to s. In that sense, it is
-// equivalent to string(s) but may be more efficient.
-func String(s []byte) string {
- if a := Lookup(s); a != 0 {
- return a.String()
- }
- return string(s)
-}
diff --git a/vendor/golang.org/x/net/html/atom/table.go b/vendor/golang.org/x/net/html/atom/table.go
deleted file mode 100644
index 2a938864cb..0000000000
--- a/vendor/golang.org/x/net/html/atom/table.go
+++ /dev/null
@@ -1,783 +0,0 @@
-// Code generated by go generate gen.go; DO NOT EDIT.
-
-//go:generate go run gen.go
-
-package atom
-
-const (
- A Atom = 0x1
- Abbr Atom = 0x4
- Accept Atom = 0x1a06
- AcceptCharset Atom = 0x1a0e
- Accesskey Atom = 0x2c09
- Acronym Atom = 0xaa07
- Action Atom = 0x27206
- Address Atom = 0x6f307
- Align Atom = 0xb105
- Allowfullscreen Atom = 0x2080f
- Allowpaymentrequest Atom = 0xc113
- Allowusermedia Atom = 0xdd0e
- Alt Atom = 0xf303
- Annotation Atom = 0x1c90a
- AnnotationXml Atom = 0x1c90e
- Applet Atom = 0x31906
- Area Atom = 0x35604
- Article Atom = 0x3fc07
- As Atom = 0x3c02
- Aside Atom = 0x10705
- Async Atom = 0xff05
- Audio Atom = 0x11505
- Autocomplete Atom = 0x2780c
- Autofocus Atom = 0x12109
- Autoplay Atom = 0x13c08
- B Atom = 0x101
- Base Atom = 0x3b04
- Basefont Atom = 0x3b08
- Bdi Atom = 0xba03
- Bdo Atom = 0x14b03
- Bgsound Atom = 0x15e07
- Big Atom = 0x17003
- Blink Atom = 0x17305
- Blockquote Atom = 0x1870a
- Body Atom = 0x2804
- Br Atom = 0x202
- Button Atom = 0x19106
- Canvas Atom = 0x10306
- Caption Atom = 0x23107
- Center Atom = 0x22006
- Challenge Atom = 0x29b09
- Charset Atom = 0x2107
- Checked Atom = 0x47907
- Cite Atom = 0x19c04
- Class Atom = 0x56405
- Code Atom = 0x5c504
- Col Atom = 0x1ab03
- Colgroup Atom = 0x1ab08
- Color Atom = 0x1bf05
- Cols Atom = 0x1c404
- Colspan Atom = 0x1c407
- Command Atom = 0x1d707
- Content Atom = 0x58b07
- Contenteditable Atom = 0x58b0f
- Contextmenu Atom = 0x3800b
- Controls Atom = 0x1de08
- Coords Atom = 0x1ea06
- Crossorigin Atom = 0x1fb0b
- Data Atom = 0x4a504
- Datalist Atom = 0x4a508
- Datetime Atom = 0x2b808
- Dd Atom = 0x2d702
- Default Atom = 0x10a07
- Defer Atom = 0x5c705
- Del Atom = 0x45203
- Desc Atom = 0x56104
- Details Atom = 0x7207
- Dfn Atom = 0x8703
- Dialog Atom = 0xbb06
- Dir Atom = 0x9303
- Dirname Atom = 0x9307
- Disabled Atom = 0x16408
- Div Atom = 0x16b03
- Dl Atom = 0x5e602
- Download Atom = 0x46308
- Draggable Atom = 0x17a09
- Dropzone Atom = 0x40508
- Dt Atom = 0x64b02
- Em Atom = 0x6e02
- Embed Atom = 0x6e05
- Enctype Atom = 0x28d07
- Face Atom = 0x21e04
- Fieldset Atom = 0x22608
- Figcaption Atom = 0x22e0a
- Figure Atom = 0x24806
- Font Atom = 0x3f04
- Footer Atom = 0xf606
- For Atom = 0x25403
- ForeignObject Atom = 0x2540d
- Foreignobject Atom = 0x2610d
- Form Atom = 0x26e04
- Formaction Atom = 0x26e0a
- Formenctype Atom = 0x2890b
- Formmethod Atom = 0x2a40a
- Formnovalidate Atom = 0x2ae0e
- Formtarget Atom = 0x2c00a
- Frame Atom = 0x8b05
- Frameset Atom = 0x8b08
- H1 Atom = 0x15c02
- H2 Atom = 0x2de02
- H3 Atom = 0x30d02
- H4 Atom = 0x34502
- H5 Atom = 0x34f02
- H6 Atom = 0x64d02
- Head Atom = 0x33104
- Header Atom = 0x33106
- Headers Atom = 0x33107
- Height Atom = 0x5206
- Hgroup Atom = 0x2ca06
- Hidden Atom = 0x2d506
- High Atom = 0x2db04
- Hr Atom = 0x15702
- Href Atom = 0x2e004
- Hreflang Atom = 0x2e008
- Html Atom = 0x5604
- HttpEquiv Atom = 0x2e80a
- I Atom = 0x601
- Icon Atom = 0x58a04
- Id Atom = 0x10902
- Iframe Atom = 0x2fc06
- Image Atom = 0x30205
- Img Atom = 0x30703
- Input Atom = 0x44b05
- Inputmode Atom = 0x44b09
- Ins Atom = 0x20403
- Integrity Atom = 0x23f09
- Is Atom = 0x16502
- Isindex Atom = 0x30f07
- Ismap Atom = 0x31605
- Itemid Atom = 0x38b06
- Itemprop Atom = 0x19d08
- Itemref Atom = 0x3cd07
- Itemscope Atom = 0x67109
- Itemtype Atom = 0x31f08
- Kbd Atom = 0xb903
- Keygen Atom = 0x3206
- Keytype Atom = 0xd607
- Kind Atom = 0x17704
- Label Atom = 0x5905
- Lang Atom = 0x2e404
- Legend Atom = 0x18106
- Li Atom = 0xb202
- Link Atom = 0x17404
- List Atom = 0x4a904
- Listing Atom = 0x4a907
- Loop Atom = 0x5d04
- Low Atom = 0xc303
- Main Atom = 0x1004
- Malignmark Atom = 0xb00a
- Manifest Atom = 0x6d708
- Map Atom = 0x31803
- Mark Atom = 0xb604
- Marquee Atom = 0x32707
- Math Atom = 0x32e04
- Max Atom = 0x33d03
- Maxlength Atom = 0x33d09
- Media Atom = 0xe605
- Mediagroup Atom = 0xe60a
- Menu Atom = 0x38704
- Menuitem Atom = 0x38708
- Meta Atom = 0x4b804
- Meter Atom = 0x9805
- Method Atom = 0x2a806
- Mglyph Atom = 0x30806
- Mi Atom = 0x34702
- Min Atom = 0x34703
- Minlength Atom = 0x34709
- Mn Atom = 0x2b102
- Mo Atom = 0xa402
- Ms Atom = 0x67402
- Mtext Atom = 0x35105
- Multiple Atom = 0x35f08
- Muted Atom = 0x36705
- Name Atom = 0x9604
- Nav Atom = 0x1303
- Nobr Atom = 0x3704
- Noembed Atom = 0x6c07
- Noframes Atom = 0x8908
- Nomodule Atom = 0xa208
- Nonce Atom = 0x1a605
- Noscript Atom = 0x21608
- Novalidate Atom = 0x2b20a
- Object Atom = 0x26806
- Ol Atom = 0x13702
- Onabort Atom = 0x19507
- Onafterprint Atom = 0x2360c
- Onautocomplete Atom = 0x2760e
- Onautocompleteerror Atom = 0x27613
- Onauxclick Atom = 0x61f0a
- Onbeforeprint Atom = 0x69e0d
- Onbeforeunload Atom = 0x6e70e
- Onblur Atom = 0x56d06
- Oncancel Atom = 0x11908
- Oncanplay Atom = 0x14d09
- Oncanplaythrough Atom = 0x14d10
- Onchange Atom = 0x41b08
- Onclick Atom = 0x2f507
- Onclose Atom = 0x36c07
- Oncontextmenu Atom = 0x37e0d
- Oncopy Atom = 0x39106
- Oncuechange Atom = 0x3970b
- Oncut Atom = 0x3a205
- Ondblclick Atom = 0x3a70a
- Ondrag Atom = 0x3b106
- Ondragend Atom = 0x3b109
- Ondragenter Atom = 0x3ba0b
- Ondragexit Atom = 0x3c50a
- Ondragleave Atom = 0x3df0b
- Ondragover Atom = 0x3ea0a
- Ondragstart Atom = 0x3f40b
- Ondrop Atom = 0x40306
- Ondurationchange Atom = 0x41310
- Onemptied Atom = 0x40a09
- Onended Atom = 0x42307
- Onerror Atom = 0x42a07
- Onfocus Atom = 0x43107
- Onhashchange Atom = 0x43d0c
- Oninput Atom = 0x44907
- Oninvalid Atom = 0x45509
- Onkeydown Atom = 0x45e09
- Onkeypress Atom = 0x46b0a
- Onkeyup Atom = 0x48007
- Onlanguagechange Atom = 0x48d10
- Onload Atom = 0x49d06
- Onloadeddata Atom = 0x49d0c
- Onloadedmetadata Atom = 0x4b010
- Onloadend Atom = 0x4c609
- Onloadstart Atom = 0x4cf0b
- Onmessage Atom = 0x4da09
- Onmessageerror Atom = 0x4da0e
- Onmousedown Atom = 0x4e80b
- Onmouseenter Atom = 0x4f30c
- Onmouseleave Atom = 0x4ff0c
- Onmousemove Atom = 0x50b0b
- Onmouseout Atom = 0x5160a
- Onmouseover Atom = 0x5230b
- Onmouseup Atom = 0x52e09
- Onmousewheel Atom = 0x53c0c
- Onoffline Atom = 0x54809
- Ononline Atom = 0x55108
- Onpagehide Atom = 0x5590a
- Onpageshow Atom = 0x5730a
- Onpaste Atom = 0x57f07
- Onpause Atom = 0x59a07
- Onplay Atom = 0x5a406
- Onplaying Atom = 0x5a409
- Onpopstate Atom = 0x5ad0a
- Onprogress Atom = 0x5b70a
- Onratechange Atom = 0x5cc0c
- Onrejectionhandled Atom = 0x5d812
- Onreset Atom = 0x5ea07
- Onresize Atom = 0x5f108
- Onscroll Atom = 0x60008
- Onsecuritypolicyviolation Atom = 0x60819
- Onseeked Atom = 0x62908
- Onseeking Atom = 0x63109
- Onselect Atom = 0x63a08
- Onshow Atom = 0x64406
- Onsort Atom = 0x64f06
- Onstalled Atom = 0x65909
- Onstorage Atom = 0x66209
- Onsubmit Atom = 0x66b08
- Onsuspend Atom = 0x67b09
- Ontimeupdate Atom = 0x400c
- Ontoggle Atom = 0x68408
- Onunhandledrejection Atom = 0x68c14
- Onunload Atom = 0x6ab08
- Onvolumechange Atom = 0x6b30e
- Onwaiting Atom = 0x6c109
- Onwheel Atom = 0x6ca07
- Open Atom = 0x1a304
- Optgroup Atom = 0x5f08
- Optimum Atom = 0x6d107
- Option Atom = 0x6e306
- Output Atom = 0x51d06
- P Atom = 0xc01
- Param Atom = 0xc05
- Pattern Atom = 0x6607
- Picture Atom = 0x7b07
- Ping Atom = 0xef04
- Placeholder Atom = 0x1310b
- Plaintext Atom = 0x1b209
- Playsinline Atom = 0x1400b
- Poster Atom = 0x2cf06
- Pre Atom = 0x47003
- Preload Atom = 0x48607
- Progress Atom = 0x5b908
- Prompt Atom = 0x53606
- Public Atom = 0x58606
- Q Atom = 0xcf01
- Radiogroup Atom = 0x30a
- Rb Atom = 0x3a02
- Readonly Atom = 0x35708
- Referrerpolicy Atom = 0x3d10e
- Rel Atom = 0x48703
- Required Atom = 0x24c08
- Reversed Atom = 0x8008
- Rows Atom = 0x9c04
- Rowspan Atom = 0x9c07
- Rp Atom = 0x23c02
- Rt Atom = 0x19a02
- Rtc Atom = 0x19a03
- Ruby Atom = 0xfb04
- S Atom = 0x2501
- Samp Atom = 0x7804
- Sandbox Atom = 0x12907
- Scope Atom = 0x67505
- Scoped Atom = 0x67506
- Script Atom = 0x21806
- Seamless Atom = 0x37108
- Section Atom = 0x56807
- Select Atom = 0x63c06
- Selected Atom = 0x63c08
- Shape Atom = 0x1e505
- Size Atom = 0x5f504
- Sizes Atom = 0x5f505
- Slot Atom = 0x1ef04
- Small Atom = 0x20605
- Sortable Atom = 0x65108
- Sorted Atom = 0x33706
- Source Atom = 0x37806
- Spacer Atom = 0x43706
- Span Atom = 0x9f04
- Spellcheck Atom = 0x4740a
- Src Atom = 0x5c003
- Srcdoc Atom = 0x5c006
- Srclang Atom = 0x5f907
- Srcset Atom = 0x6f906
- Start Atom = 0x3fa05
- Step Atom = 0x58304
- Strike Atom = 0xd206
- Strong Atom = 0x6dd06
- Style Atom = 0x6ff05
- Sub Atom = 0x66d03
- Summary Atom = 0x70407
- Sup Atom = 0x70b03
- Svg Atom = 0x70e03
- System Atom = 0x71106
- Tabindex Atom = 0x4be08
- Table Atom = 0x59505
- Target Atom = 0x2c406
- Tbody Atom = 0x2705
- Td Atom = 0x9202
- Template Atom = 0x71408
- Textarea Atom = 0x35208
- Tfoot Atom = 0xf505
- Th Atom = 0x15602
- Thead Atom = 0x33005
- Time Atom = 0x4204
- Title Atom = 0x11005
- Tr Atom = 0xcc02
- Track Atom = 0x1ba05
- Translate Atom = 0x1f209
- Tt Atom = 0x6802
- Type Atom = 0xd904
- Typemustmatch Atom = 0x2900d
- U Atom = 0xb01
- Ul Atom = 0xa702
- Updateviacache Atom = 0x460e
- Usemap Atom = 0x59e06
- Value Atom = 0x1505
- Var Atom = 0x16d03
- Video Atom = 0x2f105
- Wbr Atom = 0x57c03
- Width Atom = 0x64905
- Workertype Atom = 0x71c0a
- Wrap Atom = 0x72604
- Xmp Atom = 0x12f03
-)
-
-const hash0 = 0x81cdf10e
-
-const maxAtomLen = 25
-
-var table = [1 << 9]Atom{
- 0x1: 0xe60a, // mediagroup
- 0x2: 0x2e404, // lang
- 0x4: 0x2c09, // accesskey
- 0x5: 0x8b08, // frameset
- 0x7: 0x63a08, // onselect
- 0x8: 0x71106, // system
- 0xa: 0x64905, // width
- 0xc: 0x2890b, // formenctype
- 0xd: 0x13702, // ol
- 0xe: 0x3970b, // oncuechange
- 0x10: 0x14b03, // bdo
- 0x11: 0x11505, // audio
- 0x12: 0x17a09, // draggable
- 0x14: 0x2f105, // video
- 0x15: 0x2b102, // mn
- 0x16: 0x38704, // menu
- 0x17: 0x2cf06, // poster
- 0x19: 0xf606, // footer
- 0x1a: 0x2a806, // method
- 0x1b: 0x2b808, // datetime
- 0x1c: 0x19507, // onabort
- 0x1d: 0x460e, // updateviacache
- 0x1e: 0xff05, // async
- 0x1f: 0x49d06, // onload
- 0x21: 0x11908, // oncancel
- 0x22: 0x62908, // onseeked
- 0x23: 0x30205, // image
- 0x24: 0x5d812, // onrejectionhandled
- 0x26: 0x17404, // link
- 0x27: 0x51d06, // output
- 0x28: 0x33104, // head
- 0x29: 0x4ff0c, // onmouseleave
- 0x2a: 0x57f07, // onpaste
- 0x2b: 0x5a409, // onplaying
- 0x2c: 0x1c407, // colspan
- 0x2f: 0x1bf05, // color
- 0x30: 0x5f504, // size
- 0x31: 0x2e80a, // http-equiv
- 0x33: 0x601, // i
- 0x34: 0x5590a, // onpagehide
- 0x35: 0x68c14, // onunhandledrejection
- 0x37: 0x42a07, // onerror
- 0x3a: 0x3b08, // basefont
- 0x3f: 0x1303, // nav
- 0x40: 0x17704, // kind
- 0x41: 0x35708, // readonly
- 0x42: 0x30806, // mglyph
- 0x44: 0xb202, // li
- 0x46: 0x2d506, // hidden
- 0x47: 0x70e03, // svg
- 0x48: 0x58304, // step
- 0x49: 0x23f09, // integrity
- 0x4a: 0x58606, // public
- 0x4c: 0x1ab03, // col
- 0x4d: 0x1870a, // blockquote
- 0x4e: 0x34f02, // h5
- 0x50: 0x5b908, // progress
- 0x51: 0x5f505, // sizes
- 0x52: 0x34502, // h4
- 0x56: 0x33005, // thead
- 0x57: 0xd607, // keytype
- 0x58: 0x5b70a, // onprogress
- 0x59: 0x44b09, // inputmode
- 0x5a: 0x3b109, // ondragend
- 0x5d: 0x3a205, // oncut
- 0x5e: 0x43706, // spacer
- 0x5f: 0x1ab08, // colgroup
- 0x62: 0x16502, // is
- 0x65: 0x3c02, // as
- 0x66: 0x54809, // onoffline
- 0x67: 0x33706, // sorted
- 0x69: 0x48d10, // onlanguagechange
- 0x6c: 0x43d0c, // onhashchange
- 0x6d: 0x9604, // name
- 0x6e: 0xf505, // tfoot
- 0x6f: 0x56104, // desc
- 0x70: 0x33d03, // max
- 0x72: 0x1ea06, // coords
- 0x73: 0x30d02, // h3
- 0x74: 0x6e70e, // onbeforeunload
- 0x75: 0x9c04, // rows
- 0x76: 0x63c06, // select
- 0x77: 0x9805, // meter
- 0x78: 0x38b06, // itemid
- 0x79: 0x53c0c, // onmousewheel
- 0x7a: 0x5c006, // srcdoc
- 0x7d: 0x1ba05, // track
- 0x7f: 0x31f08, // itemtype
- 0x82: 0xa402, // mo
- 0x83: 0x41b08, // onchange
- 0x84: 0x33107, // headers
- 0x85: 0x5cc0c, // onratechange
- 0x86: 0x60819, // onsecuritypolicyviolation
- 0x88: 0x4a508, // datalist
- 0x89: 0x4e80b, // onmousedown
- 0x8a: 0x1ef04, // slot
- 0x8b: 0x4b010, // onloadedmetadata
- 0x8c: 0x1a06, // accept
- 0x8d: 0x26806, // object
- 0x91: 0x6b30e, // onvolumechange
- 0x92: 0x2107, // charset
- 0x93: 0x27613, // onautocompleteerror
- 0x94: 0xc113, // allowpaymentrequest
- 0x95: 0x2804, // body
- 0x96: 0x10a07, // default
- 0x97: 0x63c08, // selected
- 0x98: 0x21e04, // face
- 0x99: 0x1e505, // shape
- 0x9b: 0x68408, // ontoggle
- 0x9e: 0x64b02, // dt
- 0x9f: 0xb604, // mark
- 0xa1: 0xb01, // u
- 0xa4: 0x6ab08, // onunload
- 0xa5: 0x5d04, // loop
- 0xa6: 0x16408, // disabled
- 0xaa: 0x42307, // onended
- 0xab: 0xb00a, // malignmark
- 0xad: 0x67b09, // onsuspend
- 0xae: 0x35105, // mtext
- 0xaf: 0x64f06, // onsort
- 0xb0: 0x19d08, // itemprop
- 0xb3: 0x67109, // itemscope
- 0xb4: 0x17305, // blink
- 0xb6: 0x3b106, // ondrag
- 0xb7: 0xa702, // ul
- 0xb8: 0x26e04, // form
- 0xb9: 0x12907, // sandbox
- 0xba: 0x8b05, // frame
- 0xbb: 0x1505, // value
- 0xbc: 0x66209, // onstorage
- 0xbf: 0xaa07, // acronym
- 0xc0: 0x19a02, // rt
- 0xc2: 0x202, // br
- 0xc3: 0x22608, // fieldset
- 0xc4: 0x2900d, // typemustmatch
- 0xc5: 0xa208, // nomodule
- 0xc6: 0x6c07, // noembed
- 0xc7: 0x69e0d, // onbeforeprint
- 0xc8: 0x19106, // button
- 0xc9: 0x2f507, // onclick
- 0xca: 0x70407, // summary
- 0xcd: 0xfb04, // ruby
- 0xce: 0x56405, // class
- 0xcf: 0x3f40b, // ondragstart
- 0xd0: 0x23107, // caption
- 0xd4: 0xdd0e, // allowusermedia
- 0xd5: 0x4cf0b, // onloadstart
- 0xd9: 0x16b03, // div
- 0xda: 0x4a904, // list
- 0xdb: 0x32e04, // math
- 0xdc: 0x44b05, // input
- 0xdf: 0x3ea0a, // ondragover
- 0xe0: 0x2de02, // h2
- 0xe2: 0x1b209, // plaintext
- 0xe4: 0x4f30c, // onmouseenter
- 0xe7: 0x47907, // checked
- 0xe8: 0x47003, // pre
- 0xea: 0x35f08, // multiple
- 0xeb: 0xba03, // bdi
- 0xec: 0x33d09, // maxlength
- 0xed: 0xcf01, // q
- 0xee: 0x61f0a, // onauxclick
- 0xf0: 0x57c03, // wbr
- 0xf2: 0x3b04, // base
- 0xf3: 0x6e306, // option
- 0xf5: 0x41310, // ondurationchange
- 0xf7: 0x8908, // noframes
- 0xf9: 0x40508, // dropzone
- 0xfb: 0x67505, // scope
- 0xfc: 0x8008, // reversed
- 0xfd: 0x3ba0b, // ondragenter
- 0xfe: 0x3fa05, // start
- 0xff: 0x12f03, // xmp
- 0x100: 0x5f907, // srclang
- 0x101: 0x30703, // img
- 0x104: 0x101, // b
- 0x105: 0x25403, // for
- 0x106: 0x10705, // aside
- 0x107: 0x44907, // oninput
- 0x108: 0x35604, // area
- 0x109: 0x2a40a, // formmethod
- 0x10a: 0x72604, // wrap
- 0x10c: 0x23c02, // rp
- 0x10d: 0x46b0a, // onkeypress
- 0x10e: 0x6802, // tt
- 0x110: 0x34702, // mi
- 0x111: 0x36705, // muted
- 0x112: 0xf303, // alt
- 0x113: 0x5c504, // code
- 0x114: 0x6e02, // em
- 0x115: 0x3c50a, // ondragexit
- 0x117: 0x9f04, // span
- 0x119: 0x6d708, // manifest
- 0x11a: 0x38708, // menuitem
- 0x11b: 0x58b07, // content
- 0x11d: 0x6c109, // onwaiting
- 0x11f: 0x4c609, // onloadend
- 0x121: 0x37e0d, // oncontextmenu
- 0x123: 0x56d06, // onblur
- 0x124: 0x3fc07, // article
- 0x125: 0x9303, // dir
- 0x126: 0xef04, // ping
- 0x127: 0x24c08, // required
- 0x128: 0x45509, // oninvalid
- 0x129: 0xb105, // align
- 0x12b: 0x58a04, // icon
- 0x12c: 0x64d02, // h6
- 0x12d: 0x1c404, // cols
- 0x12e: 0x22e0a, // figcaption
- 0x12f: 0x45e09, // onkeydown
- 0x130: 0x66b08, // onsubmit
- 0x131: 0x14d09, // oncanplay
- 0x132: 0x70b03, // sup
- 0x133: 0xc01, // p
- 0x135: 0x40a09, // onemptied
- 0x136: 0x39106, // oncopy
- 0x137: 0x19c04, // cite
- 0x138: 0x3a70a, // ondblclick
- 0x13a: 0x50b0b, // onmousemove
- 0x13c: 0x66d03, // sub
- 0x13d: 0x48703, // rel
- 0x13e: 0x5f08, // optgroup
- 0x142: 0x9c07, // rowspan
- 0x143: 0x37806, // source
- 0x144: 0x21608, // noscript
- 0x145: 0x1a304, // open
- 0x146: 0x20403, // ins
- 0x147: 0x2540d, // foreignObject
- 0x148: 0x5ad0a, // onpopstate
- 0x14a: 0x28d07, // enctype
- 0x14b: 0x2760e, // onautocomplete
- 0x14c: 0x35208, // textarea
- 0x14e: 0x2780c, // autocomplete
- 0x14f: 0x15702, // hr
- 0x150: 0x1de08, // controls
- 0x151: 0x10902, // id
- 0x153: 0x2360c, // onafterprint
- 0x155: 0x2610d, // foreignobject
- 0x156: 0x32707, // marquee
- 0x157: 0x59a07, // onpause
- 0x158: 0x5e602, // dl
- 0x159: 0x5206, // height
- 0x15a: 0x34703, // min
- 0x15b: 0x9307, // dirname
- 0x15c: 0x1f209, // translate
- 0x15d: 0x5604, // html
- 0x15e: 0x34709, // minlength
- 0x15f: 0x48607, // preload
- 0x160: 0x71408, // template
- 0x161: 0x3df0b, // ondragleave
- 0x162: 0x3a02, // rb
- 0x164: 0x5c003, // src
- 0x165: 0x6dd06, // strong
- 0x167: 0x7804, // samp
- 0x168: 0x6f307, // address
- 0x169: 0x55108, // ononline
- 0x16b: 0x1310b, // placeholder
- 0x16c: 0x2c406, // target
- 0x16d: 0x20605, // small
- 0x16e: 0x6ca07, // onwheel
- 0x16f: 0x1c90a, // annotation
- 0x170: 0x4740a, // spellcheck
- 0x171: 0x7207, // details
- 0x172: 0x10306, // canvas
- 0x173: 0x12109, // autofocus
- 0x174: 0xc05, // param
- 0x176: 0x46308, // download
- 0x177: 0x45203, // del
- 0x178: 0x36c07, // onclose
- 0x179: 0xb903, // kbd
- 0x17a: 0x31906, // applet
- 0x17b: 0x2e004, // href
- 0x17c: 0x5f108, // onresize
- 0x17e: 0x49d0c, // onloadeddata
- 0x180: 0xcc02, // tr
- 0x181: 0x2c00a, // formtarget
- 0x182: 0x11005, // title
- 0x183: 0x6ff05, // style
- 0x184: 0xd206, // strike
- 0x185: 0x59e06, // usemap
- 0x186: 0x2fc06, // iframe
- 0x187: 0x1004, // main
- 0x189: 0x7b07, // picture
- 0x18c: 0x31605, // ismap
- 0x18e: 0x4a504, // data
- 0x18f: 0x5905, // label
- 0x191: 0x3d10e, // referrerpolicy
- 0x192: 0x15602, // th
- 0x194: 0x53606, // prompt
- 0x195: 0x56807, // section
- 0x197: 0x6d107, // optimum
- 0x198: 0x2db04, // high
- 0x199: 0x15c02, // h1
- 0x19a: 0x65909, // onstalled
- 0x19b: 0x16d03, // var
- 0x19c: 0x4204, // time
- 0x19e: 0x67402, // ms
- 0x19f: 0x33106, // header
- 0x1a0: 0x4da09, // onmessage
- 0x1a1: 0x1a605, // nonce
- 0x1a2: 0x26e0a, // formaction
- 0x1a3: 0x22006, // center
- 0x1a4: 0x3704, // nobr
- 0x1a5: 0x59505, // table
- 0x1a6: 0x4a907, // listing
- 0x1a7: 0x18106, // legend
- 0x1a9: 0x29b09, // challenge
- 0x1aa: 0x24806, // figure
- 0x1ab: 0xe605, // media
- 0x1ae: 0xd904, // type
- 0x1af: 0x3f04, // font
- 0x1b0: 0x4da0e, // onmessageerror
- 0x1b1: 0x37108, // seamless
- 0x1b2: 0x8703, // dfn
- 0x1b3: 0x5c705, // defer
- 0x1b4: 0xc303, // low
- 0x1b5: 0x19a03, // rtc
- 0x1b6: 0x5230b, // onmouseover
- 0x1b7: 0x2b20a, // novalidate
- 0x1b8: 0x71c0a, // workertype
- 0x1ba: 0x3cd07, // itemref
- 0x1bd: 0x1, // a
- 0x1be: 0x31803, // map
- 0x1bf: 0x400c, // ontimeupdate
- 0x1c0: 0x15e07, // bgsound
- 0x1c1: 0x3206, // keygen
- 0x1c2: 0x2705, // tbody
- 0x1c5: 0x64406, // onshow
- 0x1c7: 0x2501, // s
- 0x1c8: 0x6607, // pattern
- 0x1cc: 0x14d10, // oncanplaythrough
- 0x1ce: 0x2d702, // dd
- 0x1cf: 0x6f906, // srcset
- 0x1d0: 0x17003, // big
- 0x1d2: 0x65108, // sortable
- 0x1d3: 0x48007, // onkeyup
- 0x1d5: 0x5a406, // onplay
- 0x1d7: 0x4b804, // meta
- 0x1d8: 0x40306, // ondrop
- 0x1da: 0x60008, // onscroll
- 0x1db: 0x1fb0b, // crossorigin
- 0x1dc: 0x5730a, // onpageshow
- 0x1dd: 0x4, // abbr
- 0x1de: 0x9202, // td
- 0x1df: 0x58b0f, // contenteditable
- 0x1e0: 0x27206, // action
- 0x1e1: 0x1400b, // playsinline
- 0x1e2: 0x43107, // onfocus
- 0x1e3: 0x2e008, // hreflang
- 0x1e5: 0x5160a, // onmouseout
- 0x1e6: 0x5ea07, // onreset
- 0x1e7: 0x13c08, // autoplay
- 0x1e8: 0x63109, // onseeking
- 0x1ea: 0x67506, // scoped
- 0x1ec: 0x30a, // radiogroup
- 0x1ee: 0x3800b, // contextmenu
- 0x1ef: 0x52e09, // onmouseup
- 0x1f1: 0x2ca06, // hgroup
- 0x1f2: 0x2080f, // allowfullscreen
- 0x1f3: 0x4be08, // tabindex
- 0x1f6: 0x30f07, // isindex
- 0x1f7: 0x1a0e, // accept-charset
- 0x1f8: 0x2ae0e, // formnovalidate
- 0x1fb: 0x1c90e, // annotation-xml
- 0x1fc: 0x6e05, // embed
- 0x1fd: 0x21806, // script
- 0x1fe: 0xbb06, // dialog
- 0x1ff: 0x1d707, // command
-}
-
-const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobrb" +
- "asefontimeupdateviacacheightmlabelooptgroupatternoembedetail" +
- "sampictureversedfnoframesetdirnameterowspanomoduleacronymali" +
- "gnmarkbdialogallowpaymentrequestrikeytypeallowusermediagroup" +
- "ingaltfooterubyasyncanvasidefaultitleaudioncancelautofocusan" +
- "dboxmplaceholderautoplaysinlinebdoncanplaythrough1bgsoundisa" +
- "bledivarbigblinkindraggablegendblockquotebuttonabortcitempro" +
- "penoncecolgrouplaintextrackcolorcolspannotation-xmlcommandco" +
- "ntrolshapecoordslotranslatecrossoriginsmallowfullscreenoscri" +
- "ptfacenterfieldsetfigcaptionafterprintegrityfigurequiredfore" +
- "ignObjectforeignobjectformactionautocompleteerrorformenctype" +
- "mustmatchallengeformmethodformnovalidatetimeformtargethgroup" +
- "osterhiddenhigh2hreflanghttp-equivideonclickiframeimageimgly" +
- "ph3isindexismappletitemtypemarqueematheadersortedmaxlength4m" +
- "inlength5mtextareadonlymultiplemutedoncloseamlessourceoncont" +
- "extmenuitemidoncopyoncuechangeoncutondblclickondragendondrag" +
- "enterondragexitemreferrerpolicyondragleaveondragoverondragst" +
- "articleondropzonemptiedondurationchangeonendedonerroronfocus" +
- "paceronhashchangeoninputmodeloninvalidonkeydownloadonkeypres" +
- "spellcheckedonkeyupreloadonlanguagechangeonloadeddatalisting" +
- "onloadedmetadatabindexonloadendonloadstartonmessageerroronmo" +
- "usedownonmouseenteronmouseleaveonmousemoveonmouseoutputonmou" +
- "seoveronmouseupromptonmousewheelonofflineononlineonpagehides" +
- "classectionbluronpageshowbronpastepublicontenteditableonpaus" +
- "emaponplayingonpopstateonprogressrcdocodeferonratechangeonre" +
- "jectionhandledonresetonresizesrclangonscrollonsecuritypolicy" +
- "violationauxclickonseekedonseekingonselectedonshowidth6onsor" +
- "tableonstalledonstorageonsubmitemscopedonsuspendontoggleonun" +
- "handledrejectionbeforeprintonunloadonvolumechangeonwaitingon" +
- "wheeloptimumanifestrongoptionbeforeunloaddressrcsetstylesumm" +
- "arysupsvgsystemplateworkertypewrap"
diff --git a/vendor/golang.org/x/net/html/const.go b/vendor/golang.org/x/net/html/const.go
deleted file mode 100644
index ff7acf2d5b..0000000000
--- a/vendor/golang.org/x/net/html/const.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-// Section 12.2.4.2 of the HTML5 specification says "The following elements
-// have varying levels of special parsing rules".
-// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
-var isSpecialElementMap = map[string]bool{
- "address": true,
- "applet": true,
- "area": true,
- "article": true,
- "aside": true,
- "base": true,
- "basefont": true,
- "bgsound": true,
- "blockquote": true,
- "body": true,
- "br": true,
- "button": true,
- "caption": true,
- "center": true,
- "col": true,
- "colgroup": true,
- "dd": true,
- "details": true,
- "dir": true,
- "div": true,
- "dl": true,
- "dt": true,
- "embed": true,
- "fieldset": true,
- "figcaption": true,
- "figure": true,
- "footer": true,
- "form": true,
- "frame": true,
- "frameset": true,
- "h1": true,
- "h2": true,
- "h3": true,
- "h4": true,
- "h5": true,
- "h6": true,
- "head": true,
- "header": true,
- "hgroup": true,
- "hr": true,
- "html": true,
- "iframe": true,
- "img": true,
- "input": true,
- "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility.
- "li": true,
- "link": true,
- "listing": true,
- "main": true,
- "marquee": true,
- "menu": true,
- "meta": true,
- "nav": true,
- "noembed": true,
- "noframes": true,
- "noscript": true,
- "object": true,
- "ol": true,
- "p": true,
- "param": true,
- "plaintext": true,
- "pre": true,
- "script": true,
- "section": true,
- "select": true,
- "source": true,
- "style": true,
- "summary": true,
- "table": true,
- "tbody": true,
- "td": true,
- "template": true,
- "textarea": true,
- "tfoot": true,
- "th": true,
- "thead": true,
- "title": true,
- "tr": true,
- "track": true,
- "ul": true,
- "wbr": true,
- "xmp": true,
-}
-
-func isSpecialElement(element *Node) bool {
- switch element.Namespace {
- case "", "html":
- return isSpecialElementMap[element.Data]
- case "math":
- switch element.Data {
- case "mi", "mo", "mn", "ms", "mtext", "annotation-xml":
- return true
- }
- case "svg":
- switch element.Data {
- case "foreignObject", "desc", "title":
- return true
- }
- }
- return false
-}
diff --git a/vendor/golang.org/x/net/html/doc.go b/vendor/golang.org/x/net/html/doc.go
deleted file mode 100644
index 2466ae3d9a..0000000000
--- a/vendor/golang.org/x/net/html/doc.go
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package html implements an HTML5-compliant tokenizer and parser.
-
-Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
-caller's responsibility to ensure that r provides UTF-8 encoded HTML.
-
- z := html.NewTokenizer(r)
-
-Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
-which parses the next token and returns its type, or an error:
-
- for {
- tt := z.Next()
- if tt == html.ErrorToken {
- // ...
- return ...
- }
- // Process the current token.
- }
-
-There are two APIs for retrieving the current token. The high-level API is to
-call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
-allow optionally calling Raw after Next but before Token, Text, TagName, or
-TagAttr. In EBNF notation, the valid call sequence per token is:
-
- Next {Raw} [ Token | Text | TagName {TagAttr} ]
-
-Token returns an independent data structure that completely describes a token.
-Entities (such as "<") are unescaped, tag names and attribute keys are
-lower-cased, and attributes are collected into a []Attribute. For example:
-
- for {
- if z.Next() == html.ErrorToken {
- // Returning io.EOF indicates success.
- return z.Err()
- }
- emitToken(z.Token())
- }
-
-The low-level API performs fewer allocations and copies, but the contents of
-the []byte values returned by Text, TagName and TagAttr may change on the next
-call to Next. For example, to extract an HTML page's anchor text:
-
- depth := 0
- for {
- tt := z.Next()
- switch tt {
- case html.ErrorToken:
- return z.Err()
- case html.TextToken:
- if depth > 0 {
- // emitBytes should copy the []byte it receives,
- // if it doesn't process it immediately.
- emitBytes(z.Text())
- }
- case html.StartTagToken, html.EndTagToken:
- tn, _ := z.TagName()
- if len(tn) == 1 && tn[0] == 'a' {
- if tt == html.StartTagToken {
- depth++
- } else {
- depth--
- }
- }
- }
- }
-
-Parsing is done by calling Parse with an io.Reader, which returns the root of
-the parse tree (the document element) as a *Node. It is the caller's
-responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
-example, to process each anchor node in depth-first order:
-
- doc, err := html.Parse(r)
- if err != nil {
- // ...
- }
- var f func(*html.Node)
- f = func(n *html.Node) {
- if n.Type == html.ElementNode && n.Data == "a" {
- // Do something with n...
- }
- for c := n.FirstChild; c != nil; c = c.NextSibling {
- f(c)
- }
- }
- f(doc)
-
-The relevant specifications include:
-https://html.spec.whatwg.org/multipage/syntax.html and
-https://html.spec.whatwg.org/multipage/syntax.html#tokenization
-
-# Security Considerations
-
-Care should be taken when parsing and interpreting HTML, whether full documents
-or fragments, within the framework of the HTML specification, especially with
-regard to untrusted inputs.
-
-This package provides both a tokenizer and a parser, which implement the
-tokenization, and tokenization and tree construction stages of the WHATWG HTML
-parsing specification respectively. While the tokenizer parses and normalizes
-individual HTML tokens, only the parser constructs the DOM tree from the
-tokenized HTML, as described in the tree construction stage of the
-specification, dynamically modifying or extending the docuemnt's DOM tree.
-
-If your use case requires semantically well-formed HTML documents, as defined by
-the WHATWG specification, the parser should be used rather than the tokenizer.
-
-In security contexts, if trust decisions are being made using the tokenized or
-parsed content, the input must be re-serialized (for instance by using Render or
-Token.String) in order for those trust decisions to hold, as the process of
-tokenization or parsing may alter the content.
-*/
-package html // import "golang.org/x/net/html"
-
-// The tokenization algorithm implemented by this package is not a line-by-line
-// transliteration of the relatively verbose state-machine in the WHATWG
-// specification. A more direct approach is used instead, where the program
-// counter implies the state, such as whether it is tokenizing a tag or a text
-// node. Specification compliance is verified by checking expected and actual
-// outputs over a test suite rather than aiming for algorithmic fidelity.
-
-// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
-// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/vendor/golang.org/x/net/html/doctype.go b/vendor/golang.org/x/net/html/doctype.go
deleted file mode 100644
index c484e5a94f..0000000000
--- a/vendor/golang.org/x/net/html/doctype.go
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "strings"
-)
-
-// parseDoctype parses the data from a DoctypeToken into a name,
-// public identifier, and system identifier. It returns a Node whose Type
-// is DoctypeNode, whose Data is the name, and which has attributes
-// named "system" and "public" for the two identifiers if they were present.
-// quirks is whether the document should be parsed in "quirks mode".
-func parseDoctype(s string) (n *Node, quirks bool) {
- n = &Node{Type: DoctypeNode}
-
- // Find the name.
- space := strings.IndexAny(s, whitespace)
- if space == -1 {
- space = len(s)
- }
- n.Data = s[:space]
- // The comparison to "html" is case-sensitive.
- if n.Data != "html" {
- quirks = true
- }
- n.Data = strings.ToLower(n.Data)
- s = strings.TrimLeft(s[space:], whitespace)
-
- if len(s) < 6 {
- // It can't start with "PUBLIC" or "SYSTEM".
- // Ignore the rest of the string.
- return n, quirks || s != ""
- }
-
- key := strings.ToLower(s[:6])
- s = s[6:]
- for key == "public" || key == "system" {
- s = strings.TrimLeft(s, whitespace)
- if s == "" {
- break
- }
- quote := s[0]
- if quote != '"' && quote != '\'' {
- break
- }
- s = s[1:]
- q := strings.IndexRune(s, rune(quote))
- var id string
- if q == -1 {
- id = s
- s = ""
- } else {
- id = s[:q]
- s = s[q+1:]
- }
- n.Attr = append(n.Attr, Attribute{Key: key, Val: id})
- if key == "public" {
- key = "system"
- } else {
- key = ""
- }
- }
-
- if key != "" || s != "" {
- quirks = true
- } else if len(n.Attr) > 0 {
- if n.Attr[0].Key == "public" {
- public := strings.ToLower(n.Attr[0].Val)
- switch public {
- case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html":
- quirks = true
- default:
- for _, q := range quirkyIDs {
- if strings.HasPrefix(public, q) {
- quirks = true
- break
- }
- }
- }
- // The following two public IDs only cause quirks mode if there is no system ID.
- if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") ||
- strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) {
- quirks = true
- }
- }
- if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
- strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" {
- quirks = true
- }
- }
-
- return n, quirks
-}
-
-// quirkyIDs is a list of public doctype identifiers that cause a document
-// to be interpreted in quirks mode. The identifiers should be in lower case.
-var quirkyIDs = []string{
- "+//silmaril//dtd html pro v0r11 19970101//",
- "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
- "-//as//dtd html 3.0 aswedit + extensions//",
- "-//ietf//dtd html 2.0 level 1//",
- "-//ietf//dtd html 2.0 level 2//",
- "-//ietf//dtd html 2.0 strict level 1//",
- "-//ietf//dtd html 2.0 strict level 2//",
- "-//ietf//dtd html 2.0 strict//",
- "-//ietf//dtd html 2.0//",
- "-//ietf//dtd html 2.1e//",
- "-//ietf//dtd html 3.0//",
- "-//ietf//dtd html 3.2 final//",
- "-//ietf//dtd html 3.2//",
- "-//ietf//dtd html 3//",
- "-//ietf//dtd html level 0//",
- "-//ietf//dtd html level 1//",
- "-//ietf//dtd html level 2//",
- "-//ietf//dtd html level 3//",
- "-//ietf//dtd html strict level 0//",
- "-//ietf//dtd html strict level 1//",
- "-//ietf//dtd html strict level 2//",
- "-//ietf//dtd html strict level 3//",
- "-//ietf//dtd html strict//",
- "-//ietf//dtd html//",
- "-//metrius//dtd metrius presentational//",
- "-//microsoft//dtd internet explorer 2.0 html strict//",
- "-//microsoft//dtd internet explorer 2.0 html//",
- "-//microsoft//dtd internet explorer 2.0 tables//",
- "-//microsoft//dtd internet explorer 3.0 html strict//",
- "-//microsoft//dtd internet explorer 3.0 html//",
- "-//microsoft//dtd internet explorer 3.0 tables//",
- "-//netscape comm. corp.//dtd html//",
- "-//netscape comm. corp.//dtd strict html//",
- "-//o'reilly and associates//dtd html 2.0//",
- "-//o'reilly and associates//dtd html extended 1.0//",
- "-//o'reilly and associates//dtd html extended relaxed 1.0//",
- "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
- "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
- "-//spyglass//dtd html 2.0 extended//",
- "-//sq//dtd html 2.0 hotmetal + extensions//",
- "-//sun microsystems corp.//dtd hotjava html//",
- "-//sun microsystems corp.//dtd hotjava strict html//",
- "-//w3c//dtd html 3 1995-03-24//",
- "-//w3c//dtd html 3.2 draft//",
- "-//w3c//dtd html 3.2 final//",
- "-//w3c//dtd html 3.2//",
- "-//w3c//dtd html 3.2s draft//",
- "-//w3c//dtd html 4.0 frameset//",
- "-//w3c//dtd html 4.0 transitional//",
- "-//w3c//dtd html experimental 19960712//",
- "-//w3c//dtd html experimental 970421//",
- "-//w3c//dtd w3 html//",
- "-//w3o//dtd w3 html 3.0//",
- "-//webtechs//dtd mozilla html 2.0//",
- "-//webtechs//dtd mozilla html//",
-}
diff --git a/vendor/golang.org/x/net/html/entity.go b/vendor/golang.org/x/net/html/entity.go
deleted file mode 100644
index b628880a01..0000000000
--- a/vendor/golang.org/x/net/html/entity.go
+++ /dev/null
@@ -1,2253 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-// All entities that do not end with ';' are 6 or fewer bytes long.
-const longestEntityWithoutSemicolon = 6
-
-// entity is a map from HTML entity names to their values. The semicolon matters:
-// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references
-// lists both "amp" and "amp;" as two separate entries.
-//
-// Note that the HTML5 list is larger than the HTML4 list at
-// http://www.w3.org/TR/html4/sgml/entities.html
-var entity = map[string]rune{
- "AElig;": '\U000000C6',
- "AMP;": '\U00000026',
- "Aacute;": '\U000000C1',
- "Abreve;": '\U00000102',
- "Acirc;": '\U000000C2',
- "Acy;": '\U00000410',
- "Afr;": '\U0001D504',
- "Agrave;": '\U000000C0',
- "Alpha;": '\U00000391',
- "Amacr;": '\U00000100',
- "And;": '\U00002A53',
- "Aogon;": '\U00000104',
- "Aopf;": '\U0001D538',
- "ApplyFunction;": '\U00002061',
- "Aring;": '\U000000C5',
- "Ascr;": '\U0001D49C',
- "Assign;": '\U00002254',
- "Atilde;": '\U000000C3',
- "Auml;": '\U000000C4',
- "Backslash;": '\U00002216',
- "Barv;": '\U00002AE7',
- "Barwed;": '\U00002306',
- "Bcy;": '\U00000411',
- "Because;": '\U00002235',
- "Bernoullis;": '\U0000212C',
- "Beta;": '\U00000392',
- "Bfr;": '\U0001D505',
- "Bopf;": '\U0001D539',
- "Breve;": '\U000002D8',
- "Bscr;": '\U0000212C',
- "Bumpeq;": '\U0000224E',
- "CHcy;": '\U00000427',
- "COPY;": '\U000000A9',
- "Cacute;": '\U00000106',
- "Cap;": '\U000022D2',
- "CapitalDifferentialD;": '\U00002145',
- "Cayleys;": '\U0000212D',
- "Ccaron;": '\U0000010C',
- "Ccedil;": '\U000000C7',
- "Ccirc;": '\U00000108',
- "Cconint;": '\U00002230',
- "Cdot;": '\U0000010A',
- "Cedilla;": '\U000000B8',
- "CenterDot;": '\U000000B7',
- "Cfr;": '\U0000212D',
- "Chi;": '\U000003A7',
- "CircleDot;": '\U00002299',
- "CircleMinus;": '\U00002296',
- "CirclePlus;": '\U00002295',
- "CircleTimes;": '\U00002297',
- "ClockwiseContourIntegral;": '\U00002232',
- "CloseCurlyDoubleQuote;": '\U0000201D',
- "CloseCurlyQuote;": '\U00002019',
- "Colon;": '\U00002237',
- "Colone;": '\U00002A74',
- "Congruent;": '\U00002261',
- "Conint;": '\U0000222F',
- "ContourIntegral;": '\U0000222E',
- "Copf;": '\U00002102',
- "Coproduct;": '\U00002210',
- "CounterClockwiseContourIntegral;": '\U00002233',
- "Cross;": '\U00002A2F',
- "Cscr;": '\U0001D49E',
- "Cup;": '\U000022D3',
- "CupCap;": '\U0000224D',
- "DD;": '\U00002145',
- "DDotrahd;": '\U00002911',
- "DJcy;": '\U00000402',
- "DScy;": '\U00000405',
- "DZcy;": '\U0000040F',
- "Dagger;": '\U00002021',
- "Darr;": '\U000021A1',
- "Dashv;": '\U00002AE4',
- "Dcaron;": '\U0000010E',
- "Dcy;": '\U00000414',
- "Del;": '\U00002207',
- "Delta;": '\U00000394',
- "Dfr;": '\U0001D507',
- "DiacriticalAcute;": '\U000000B4',
- "DiacriticalDot;": '\U000002D9',
- "DiacriticalDoubleAcute;": '\U000002DD',
- "DiacriticalGrave;": '\U00000060',
- "DiacriticalTilde;": '\U000002DC',
- "Diamond;": '\U000022C4',
- "DifferentialD;": '\U00002146',
- "Dopf;": '\U0001D53B',
- "Dot;": '\U000000A8',
- "DotDot;": '\U000020DC',
- "DotEqual;": '\U00002250',
- "DoubleContourIntegral;": '\U0000222F',
- "DoubleDot;": '\U000000A8',
- "DoubleDownArrow;": '\U000021D3',
- "DoubleLeftArrow;": '\U000021D0',
- "DoubleLeftRightArrow;": '\U000021D4',
- "DoubleLeftTee;": '\U00002AE4',
- "DoubleLongLeftArrow;": '\U000027F8',
- "DoubleLongLeftRightArrow;": '\U000027FA',
- "DoubleLongRightArrow;": '\U000027F9',
- "DoubleRightArrow;": '\U000021D2',
- "DoubleRightTee;": '\U000022A8',
- "DoubleUpArrow;": '\U000021D1',
- "DoubleUpDownArrow;": '\U000021D5',
- "DoubleVerticalBar;": '\U00002225',
- "DownArrow;": '\U00002193',
- "DownArrowBar;": '\U00002913',
- "DownArrowUpArrow;": '\U000021F5',
- "DownBreve;": '\U00000311',
- "DownLeftRightVector;": '\U00002950',
- "DownLeftTeeVector;": '\U0000295E',
- "DownLeftVector;": '\U000021BD',
- "DownLeftVectorBar;": '\U00002956',
- "DownRightTeeVector;": '\U0000295F',
- "DownRightVector;": '\U000021C1',
- "DownRightVectorBar;": '\U00002957',
- "DownTee;": '\U000022A4',
- "DownTeeArrow;": '\U000021A7',
- "Downarrow;": '\U000021D3',
- "Dscr;": '\U0001D49F',
- "Dstrok;": '\U00000110',
- "ENG;": '\U0000014A',
- "ETH;": '\U000000D0',
- "Eacute;": '\U000000C9',
- "Ecaron;": '\U0000011A',
- "Ecirc;": '\U000000CA',
- "Ecy;": '\U0000042D',
- "Edot;": '\U00000116',
- "Efr;": '\U0001D508',
- "Egrave;": '\U000000C8',
- "Element;": '\U00002208',
- "Emacr;": '\U00000112',
- "EmptySmallSquare;": '\U000025FB',
- "EmptyVerySmallSquare;": '\U000025AB',
- "Eogon;": '\U00000118',
- "Eopf;": '\U0001D53C',
- "Epsilon;": '\U00000395',
- "Equal;": '\U00002A75',
- "EqualTilde;": '\U00002242',
- "Equilibrium;": '\U000021CC',
- "Escr;": '\U00002130',
- "Esim;": '\U00002A73',
- "Eta;": '\U00000397',
- "Euml;": '\U000000CB',
- "Exists;": '\U00002203',
- "ExponentialE;": '\U00002147',
- "Fcy;": '\U00000424',
- "Ffr;": '\U0001D509',
- "FilledSmallSquare;": '\U000025FC',
- "FilledVerySmallSquare;": '\U000025AA',
- "Fopf;": '\U0001D53D',
- "ForAll;": '\U00002200',
- "Fouriertrf;": '\U00002131',
- "Fscr;": '\U00002131',
- "GJcy;": '\U00000403',
- "GT;": '\U0000003E',
- "Gamma;": '\U00000393',
- "Gammad;": '\U000003DC',
- "Gbreve;": '\U0000011E',
- "Gcedil;": '\U00000122',
- "Gcirc;": '\U0000011C',
- "Gcy;": '\U00000413',
- "Gdot;": '\U00000120',
- "Gfr;": '\U0001D50A',
- "Gg;": '\U000022D9',
- "Gopf;": '\U0001D53E',
- "GreaterEqual;": '\U00002265',
- "GreaterEqualLess;": '\U000022DB',
- "GreaterFullEqual;": '\U00002267',
- "GreaterGreater;": '\U00002AA2',
- "GreaterLess;": '\U00002277',
- "GreaterSlantEqual;": '\U00002A7E',
- "GreaterTilde;": '\U00002273',
- "Gscr;": '\U0001D4A2',
- "Gt;": '\U0000226B',
- "HARDcy;": '\U0000042A',
- "Hacek;": '\U000002C7',
- "Hat;": '\U0000005E',
- "Hcirc;": '\U00000124',
- "Hfr;": '\U0000210C',
- "HilbertSpace;": '\U0000210B',
- "Hopf;": '\U0000210D',
- "HorizontalLine;": '\U00002500',
- "Hscr;": '\U0000210B',
- "Hstrok;": '\U00000126',
- "HumpDownHump;": '\U0000224E',
- "HumpEqual;": '\U0000224F',
- "IEcy;": '\U00000415',
- "IJlig;": '\U00000132',
- "IOcy;": '\U00000401',
- "Iacute;": '\U000000CD',
- "Icirc;": '\U000000CE',
- "Icy;": '\U00000418',
- "Idot;": '\U00000130',
- "Ifr;": '\U00002111',
- "Igrave;": '\U000000CC',
- "Im;": '\U00002111',
- "Imacr;": '\U0000012A',
- "ImaginaryI;": '\U00002148',
- "Implies;": '\U000021D2',
- "Int;": '\U0000222C',
- "Integral;": '\U0000222B',
- "Intersection;": '\U000022C2',
- "InvisibleComma;": '\U00002063',
- "InvisibleTimes;": '\U00002062',
- "Iogon;": '\U0000012E',
- "Iopf;": '\U0001D540',
- "Iota;": '\U00000399',
- "Iscr;": '\U00002110',
- "Itilde;": '\U00000128',
- "Iukcy;": '\U00000406',
- "Iuml;": '\U000000CF',
- "Jcirc;": '\U00000134',
- "Jcy;": '\U00000419',
- "Jfr;": '\U0001D50D',
- "Jopf;": '\U0001D541',
- "Jscr;": '\U0001D4A5',
- "Jsercy;": '\U00000408',
- "Jukcy;": '\U00000404',
- "KHcy;": '\U00000425',
- "KJcy;": '\U0000040C',
- "Kappa;": '\U0000039A',
- "Kcedil;": '\U00000136',
- "Kcy;": '\U0000041A',
- "Kfr;": '\U0001D50E',
- "Kopf;": '\U0001D542',
- "Kscr;": '\U0001D4A6',
- "LJcy;": '\U00000409',
- "LT;": '\U0000003C',
- "Lacute;": '\U00000139',
- "Lambda;": '\U0000039B',
- "Lang;": '\U000027EA',
- "Laplacetrf;": '\U00002112',
- "Larr;": '\U0000219E',
- "Lcaron;": '\U0000013D',
- "Lcedil;": '\U0000013B',
- "Lcy;": '\U0000041B',
- "LeftAngleBracket;": '\U000027E8',
- "LeftArrow;": '\U00002190',
- "LeftArrowBar;": '\U000021E4',
- "LeftArrowRightArrow;": '\U000021C6',
- "LeftCeiling;": '\U00002308',
- "LeftDoubleBracket;": '\U000027E6',
- "LeftDownTeeVector;": '\U00002961',
- "LeftDownVector;": '\U000021C3',
- "LeftDownVectorBar;": '\U00002959',
- "LeftFloor;": '\U0000230A',
- "LeftRightArrow;": '\U00002194',
- "LeftRightVector;": '\U0000294E',
- "LeftTee;": '\U000022A3',
- "LeftTeeArrow;": '\U000021A4',
- "LeftTeeVector;": '\U0000295A',
- "LeftTriangle;": '\U000022B2',
- "LeftTriangleBar;": '\U000029CF',
- "LeftTriangleEqual;": '\U000022B4',
- "LeftUpDownVector;": '\U00002951',
- "LeftUpTeeVector;": '\U00002960',
- "LeftUpVector;": '\U000021BF',
- "LeftUpVectorBar;": '\U00002958',
- "LeftVector;": '\U000021BC',
- "LeftVectorBar;": '\U00002952',
- "Leftarrow;": '\U000021D0',
- "Leftrightarrow;": '\U000021D4',
- "LessEqualGreater;": '\U000022DA',
- "LessFullEqual;": '\U00002266',
- "LessGreater;": '\U00002276',
- "LessLess;": '\U00002AA1',
- "LessSlantEqual;": '\U00002A7D',
- "LessTilde;": '\U00002272',
- "Lfr;": '\U0001D50F',
- "Ll;": '\U000022D8',
- "Lleftarrow;": '\U000021DA',
- "Lmidot;": '\U0000013F',
- "LongLeftArrow;": '\U000027F5',
- "LongLeftRightArrow;": '\U000027F7',
- "LongRightArrow;": '\U000027F6',
- "Longleftarrow;": '\U000027F8',
- "Longleftrightarrow;": '\U000027FA',
- "Longrightarrow;": '\U000027F9',
- "Lopf;": '\U0001D543',
- "LowerLeftArrow;": '\U00002199',
- "LowerRightArrow;": '\U00002198',
- "Lscr;": '\U00002112',
- "Lsh;": '\U000021B0',
- "Lstrok;": '\U00000141',
- "Lt;": '\U0000226A',
- "Map;": '\U00002905',
- "Mcy;": '\U0000041C',
- "MediumSpace;": '\U0000205F',
- "Mellintrf;": '\U00002133',
- "Mfr;": '\U0001D510',
- "MinusPlus;": '\U00002213',
- "Mopf;": '\U0001D544',
- "Mscr;": '\U00002133',
- "Mu;": '\U0000039C',
- "NJcy;": '\U0000040A',
- "Nacute;": '\U00000143',
- "Ncaron;": '\U00000147',
- "Ncedil;": '\U00000145',
- "Ncy;": '\U0000041D',
- "NegativeMediumSpace;": '\U0000200B',
- "NegativeThickSpace;": '\U0000200B',
- "NegativeThinSpace;": '\U0000200B',
- "NegativeVeryThinSpace;": '\U0000200B',
- "NestedGreaterGreater;": '\U0000226B',
- "NestedLessLess;": '\U0000226A',
- "NewLine;": '\U0000000A',
- "Nfr;": '\U0001D511',
- "NoBreak;": '\U00002060',
- "NonBreakingSpace;": '\U000000A0',
- "Nopf;": '\U00002115',
- "Not;": '\U00002AEC',
- "NotCongruent;": '\U00002262',
- "NotCupCap;": '\U0000226D',
- "NotDoubleVerticalBar;": '\U00002226',
- "NotElement;": '\U00002209',
- "NotEqual;": '\U00002260',
- "NotExists;": '\U00002204',
- "NotGreater;": '\U0000226F',
- "NotGreaterEqual;": '\U00002271',
- "NotGreaterLess;": '\U00002279',
- "NotGreaterTilde;": '\U00002275',
- "NotLeftTriangle;": '\U000022EA',
- "NotLeftTriangleEqual;": '\U000022EC',
- "NotLess;": '\U0000226E',
- "NotLessEqual;": '\U00002270',
- "NotLessGreater;": '\U00002278',
- "NotLessTilde;": '\U00002274',
- "NotPrecedes;": '\U00002280',
- "NotPrecedesSlantEqual;": '\U000022E0',
- "NotReverseElement;": '\U0000220C',
- "NotRightTriangle;": '\U000022EB',
- "NotRightTriangleEqual;": '\U000022ED',
- "NotSquareSubsetEqual;": '\U000022E2',
- "NotSquareSupersetEqual;": '\U000022E3',
- "NotSubsetEqual;": '\U00002288',
- "NotSucceeds;": '\U00002281',
- "NotSucceedsSlantEqual;": '\U000022E1',
- "NotSupersetEqual;": '\U00002289',
- "NotTilde;": '\U00002241',
- "NotTildeEqual;": '\U00002244',
- "NotTildeFullEqual;": '\U00002247',
- "NotTildeTilde;": '\U00002249',
- "NotVerticalBar;": '\U00002224',
- "Nscr;": '\U0001D4A9',
- "Ntilde;": '\U000000D1',
- "Nu;": '\U0000039D',
- "OElig;": '\U00000152',
- "Oacute;": '\U000000D3',
- "Ocirc;": '\U000000D4',
- "Ocy;": '\U0000041E',
- "Odblac;": '\U00000150',
- "Ofr;": '\U0001D512',
- "Ograve;": '\U000000D2',
- "Omacr;": '\U0000014C',
- "Omega;": '\U000003A9',
- "Omicron;": '\U0000039F',
- "Oopf;": '\U0001D546',
- "OpenCurlyDoubleQuote;": '\U0000201C',
- "OpenCurlyQuote;": '\U00002018',
- "Or;": '\U00002A54',
- "Oscr;": '\U0001D4AA',
- "Oslash;": '\U000000D8',
- "Otilde;": '\U000000D5',
- "Otimes;": '\U00002A37',
- "Ouml;": '\U000000D6',
- "OverBar;": '\U0000203E',
- "OverBrace;": '\U000023DE',
- "OverBracket;": '\U000023B4',
- "OverParenthesis;": '\U000023DC',
- "PartialD;": '\U00002202',
- "Pcy;": '\U0000041F',
- "Pfr;": '\U0001D513',
- "Phi;": '\U000003A6',
- "Pi;": '\U000003A0',
- "PlusMinus;": '\U000000B1',
- "Poincareplane;": '\U0000210C',
- "Popf;": '\U00002119',
- "Pr;": '\U00002ABB',
- "Precedes;": '\U0000227A',
- "PrecedesEqual;": '\U00002AAF',
- "PrecedesSlantEqual;": '\U0000227C',
- "PrecedesTilde;": '\U0000227E',
- "Prime;": '\U00002033',
- "Product;": '\U0000220F',
- "Proportion;": '\U00002237',
- "Proportional;": '\U0000221D',
- "Pscr;": '\U0001D4AB',
- "Psi;": '\U000003A8',
- "QUOT;": '\U00000022',
- "Qfr;": '\U0001D514',
- "Qopf;": '\U0000211A',
- "Qscr;": '\U0001D4AC',
- "RBarr;": '\U00002910',
- "REG;": '\U000000AE',
- "Racute;": '\U00000154',
- "Rang;": '\U000027EB',
- "Rarr;": '\U000021A0',
- "Rarrtl;": '\U00002916',
- "Rcaron;": '\U00000158',
- "Rcedil;": '\U00000156',
- "Rcy;": '\U00000420',
- "Re;": '\U0000211C',
- "ReverseElement;": '\U0000220B',
- "ReverseEquilibrium;": '\U000021CB',
- "ReverseUpEquilibrium;": '\U0000296F',
- "Rfr;": '\U0000211C',
- "Rho;": '\U000003A1',
- "RightAngleBracket;": '\U000027E9',
- "RightArrow;": '\U00002192',
- "RightArrowBar;": '\U000021E5',
- "RightArrowLeftArrow;": '\U000021C4',
- "RightCeiling;": '\U00002309',
- "RightDoubleBracket;": '\U000027E7',
- "RightDownTeeVector;": '\U0000295D',
- "RightDownVector;": '\U000021C2',
- "RightDownVectorBar;": '\U00002955',
- "RightFloor;": '\U0000230B',
- "RightTee;": '\U000022A2',
- "RightTeeArrow;": '\U000021A6',
- "RightTeeVector;": '\U0000295B',
- "RightTriangle;": '\U000022B3',
- "RightTriangleBar;": '\U000029D0',
- "RightTriangleEqual;": '\U000022B5',
- "RightUpDownVector;": '\U0000294F',
- "RightUpTeeVector;": '\U0000295C',
- "RightUpVector;": '\U000021BE',
- "RightUpVectorBar;": '\U00002954',
- "RightVector;": '\U000021C0',
- "RightVectorBar;": '\U00002953',
- "Rightarrow;": '\U000021D2',
- "Ropf;": '\U0000211D',
- "RoundImplies;": '\U00002970',
- "Rrightarrow;": '\U000021DB',
- "Rscr;": '\U0000211B',
- "Rsh;": '\U000021B1',
- "RuleDelayed;": '\U000029F4',
- "SHCHcy;": '\U00000429',
- "SHcy;": '\U00000428',
- "SOFTcy;": '\U0000042C',
- "Sacute;": '\U0000015A',
- "Sc;": '\U00002ABC',
- "Scaron;": '\U00000160',
- "Scedil;": '\U0000015E',
- "Scirc;": '\U0000015C',
- "Scy;": '\U00000421',
- "Sfr;": '\U0001D516',
- "ShortDownArrow;": '\U00002193',
- "ShortLeftArrow;": '\U00002190',
- "ShortRightArrow;": '\U00002192',
- "ShortUpArrow;": '\U00002191',
- "Sigma;": '\U000003A3',
- "SmallCircle;": '\U00002218',
- "Sopf;": '\U0001D54A',
- "Sqrt;": '\U0000221A',
- "Square;": '\U000025A1',
- "SquareIntersection;": '\U00002293',
- "SquareSubset;": '\U0000228F',
- "SquareSubsetEqual;": '\U00002291',
- "SquareSuperset;": '\U00002290',
- "SquareSupersetEqual;": '\U00002292',
- "SquareUnion;": '\U00002294',
- "Sscr;": '\U0001D4AE',
- "Star;": '\U000022C6',
- "Sub;": '\U000022D0',
- "Subset;": '\U000022D0',
- "SubsetEqual;": '\U00002286',
- "Succeeds;": '\U0000227B',
- "SucceedsEqual;": '\U00002AB0',
- "SucceedsSlantEqual;": '\U0000227D',
- "SucceedsTilde;": '\U0000227F',
- "SuchThat;": '\U0000220B',
- "Sum;": '\U00002211',
- "Sup;": '\U000022D1',
- "Superset;": '\U00002283',
- "SupersetEqual;": '\U00002287',
- "Supset;": '\U000022D1',
- "THORN;": '\U000000DE',
- "TRADE;": '\U00002122',
- "TSHcy;": '\U0000040B',
- "TScy;": '\U00000426',
- "Tab;": '\U00000009',
- "Tau;": '\U000003A4',
- "Tcaron;": '\U00000164',
- "Tcedil;": '\U00000162',
- "Tcy;": '\U00000422',
- "Tfr;": '\U0001D517',
- "Therefore;": '\U00002234',
- "Theta;": '\U00000398',
- "ThinSpace;": '\U00002009',
- "Tilde;": '\U0000223C',
- "TildeEqual;": '\U00002243',
- "TildeFullEqual;": '\U00002245',
- "TildeTilde;": '\U00002248',
- "Topf;": '\U0001D54B',
- "TripleDot;": '\U000020DB',
- "Tscr;": '\U0001D4AF',
- "Tstrok;": '\U00000166',
- "Uacute;": '\U000000DA',
- "Uarr;": '\U0000219F',
- "Uarrocir;": '\U00002949',
- "Ubrcy;": '\U0000040E',
- "Ubreve;": '\U0000016C',
- "Ucirc;": '\U000000DB',
- "Ucy;": '\U00000423',
- "Udblac;": '\U00000170',
- "Ufr;": '\U0001D518',
- "Ugrave;": '\U000000D9',
- "Umacr;": '\U0000016A',
- "UnderBar;": '\U0000005F',
- "UnderBrace;": '\U000023DF',
- "UnderBracket;": '\U000023B5',
- "UnderParenthesis;": '\U000023DD',
- "Union;": '\U000022C3',
- "UnionPlus;": '\U0000228E',
- "Uogon;": '\U00000172',
- "Uopf;": '\U0001D54C',
- "UpArrow;": '\U00002191',
- "UpArrowBar;": '\U00002912',
- "UpArrowDownArrow;": '\U000021C5',
- "UpDownArrow;": '\U00002195',
- "UpEquilibrium;": '\U0000296E',
- "UpTee;": '\U000022A5',
- "UpTeeArrow;": '\U000021A5',
- "Uparrow;": '\U000021D1',
- "Updownarrow;": '\U000021D5',
- "UpperLeftArrow;": '\U00002196',
- "UpperRightArrow;": '\U00002197',
- "Upsi;": '\U000003D2',
- "Upsilon;": '\U000003A5',
- "Uring;": '\U0000016E',
- "Uscr;": '\U0001D4B0',
- "Utilde;": '\U00000168',
- "Uuml;": '\U000000DC',
- "VDash;": '\U000022AB',
- "Vbar;": '\U00002AEB',
- "Vcy;": '\U00000412',
- "Vdash;": '\U000022A9',
- "Vdashl;": '\U00002AE6',
- "Vee;": '\U000022C1',
- "Verbar;": '\U00002016',
- "Vert;": '\U00002016',
- "VerticalBar;": '\U00002223',
- "VerticalLine;": '\U0000007C',
- "VerticalSeparator;": '\U00002758',
- "VerticalTilde;": '\U00002240',
- "VeryThinSpace;": '\U0000200A',
- "Vfr;": '\U0001D519',
- "Vopf;": '\U0001D54D',
- "Vscr;": '\U0001D4B1',
- "Vvdash;": '\U000022AA',
- "Wcirc;": '\U00000174',
- "Wedge;": '\U000022C0',
- "Wfr;": '\U0001D51A',
- "Wopf;": '\U0001D54E',
- "Wscr;": '\U0001D4B2',
- "Xfr;": '\U0001D51B',
- "Xi;": '\U0000039E',
- "Xopf;": '\U0001D54F',
- "Xscr;": '\U0001D4B3',
- "YAcy;": '\U0000042F',
- "YIcy;": '\U00000407',
- "YUcy;": '\U0000042E',
- "Yacute;": '\U000000DD',
- "Ycirc;": '\U00000176',
- "Ycy;": '\U0000042B',
- "Yfr;": '\U0001D51C',
- "Yopf;": '\U0001D550',
- "Yscr;": '\U0001D4B4',
- "Yuml;": '\U00000178',
- "ZHcy;": '\U00000416',
- "Zacute;": '\U00000179',
- "Zcaron;": '\U0000017D',
- "Zcy;": '\U00000417',
- "Zdot;": '\U0000017B',
- "ZeroWidthSpace;": '\U0000200B',
- "Zeta;": '\U00000396',
- "Zfr;": '\U00002128',
- "Zopf;": '\U00002124',
- "Zscr;": '\U0001D4B5',
- "aacute;": '\U000000E1',
- "abreve;": '\U00000103',
- "ac;": '\U0000223E',
- "acd;": '\U0000223F',
- "acirc;": '\U000000E2',
- "acute;": '\U000000B4',
- "acy;": '\U00000430',
- "aelig;": '\U000000E6',
- "af;": '\U00002061',
- "afr;": '\U0001D51E',
- "agrave;": '\U000000E0',
- "alefsym;": '\U00002135',
- "aleph;": '\U00002135',
- "alpha;": '\U000003B1',
- "amacr;": '\U00000101',
- "amalg;": '\U00002A3F',
- "amp;": '\U00000026',
- "and;": '\U00002227',
- "andand;": '\U00002A55',
- "andd;": '\U00002A5C',
- "andslope;": '\U00002A58',
- "andv;": '\U00002A5A',
- "ang;": '\U00002220',
- "ange;": '\U000029A4',
- "angle;": '\U00002220',
- "angmsd;": '\U00002221',
- "angmsdaa;": '\U000029A8',
- "angmsdab;": '\U000029A9',
- "angmsdac;": '\U000029AA',
- "angmsdad;": '\U000029AB',
- "angmsdae;": '\U000029AC',
- "angmsdaf;": '\U000029AD',
- "angmsdag;": '\U000029AE',
- "angmsdah;": '\U000029AF',
- "angrt;": '\U0000221F',
- "angrtvb;": '\U000022BE',
- "angrtvbd;": '\U0000299D',
- "angsph;": '\U00002222',
- "angst;": '\U000000C5',
- "angzarr;": '\U0000237C',
- "aogon;": '\U00000105',
- "aopf;": '\U0001D552',
- "ap;": '\U00002248',
- "apE;": '\U00002A70',
- "apacir;": '\U00002A6F',
- "ape;": '\U0000224A',
- "apid;": '\U0000224B',
- "apos;": '\U00000027',
- "approx;": '\U00002248',
- "approxeq;": '\U0000224A',
- "aring;": '\U000000E5',
- "ascr;": '\U0001D4B6',
- "ast;": '\U0000002A',
- "asymp;": '\U00002248',
- "asympeq;": '\U0000224D',
- "atilde;": '\U000000E3',
- "auml;": '\U000000E4',
- "awconint;": '\U00002233',
- "awint;": '\U00002A11',
- "bNot;": '\U00002AED',
- "backcong;": '\U0000224C',
- "backepsilon;": '\U000003F6',
- "backprime;": '\U00002035',
- "backsim;": '\U0000223D',
- "backsimeq;": '\U000022CD',
- "barvee;": '\U000022BD',
- "barwed;": '\U00002305',
- "barwedge;": '\U00002305',
- "bbrk;": '\U000023B5',
- "bbrktbrk;": '\U000023B6',
- "bcong;": '\U0000224C',
- "bcy;": '\U00000431',
- "bdquo;": '\U0000201E',
- "becaus;": '\U00002235',
- "because;": '\U00002235',
- "bemptyv;": '\U000029B0',
- "bepsi;": '\U000003F6',
- "bernou;": '\U0000212C',
- "beta;": '\U000003B2',
- "beth;": '\U00002136',
- "between;": '\U0000226C',
- "bfr;": '\U0001D51F',
- "bigcap;": '\U000022C2',
- "bigcirc;": '\U000025EF',
- "bigcup;": '\U000022C3',
- "bigodot;": '\U00002A00',
- "bigoplus;": '\U00002A01',
- "bigotimes;": '\U00002A02',
- "bigsqcup;": '\U00002A06',
- "bigstar;": '\U00002605',
- "bigtriangledown;": '\U000025BD',
- "bigtriangleup;": '\U000025B3',
- "biguplus;": '\U00002A04',
- "bigvee;": '\U000022C1',
- "bigwedge;": '\U000022C0',
- "bkarow;": '\U0000290D',
- "blacklozenge;": '\U000029EB',
- "blacksquare;": '\U000025AA',
- "blacktriangle;": '\U000025B4',
- "blacktriangledown;": '\U000025BE',
- "blacktriangleleft;": '\U000025C2',
- "blacktriangleright;": '\U000025B8',
- "blank;": '\U00002423',
- "blk12;": '\U00002592',
- "blk14;": '\U00002591',
- "blk34;": '\U00002593',
- "block;": '\U00002588',
- "bnot;": '\U00002310',
- "bopf;": '\U0001D553',
- "bot;": '\U000022A5',
- "bottom;": '\U000022A5',
- "bowtie;": '\U000022C8',
- "boxDL;": '\U00002557',
- "boxDR;": '\U00002554',
- "boxDl;": '\U00002556',
- "boxDr;": '\U00002553',
- "boxH;": '\U00002550',
- "boxHD;": '\U00002566',
- "boxHU;": '\U00002569',
- "boxHd;": '\U00002564',
- "boxHu;": '\U00002567',
- "boxUL;": '\U0000255D',
- "boxUR;": '\U0000255A',
- "boxUl;": '\U0000255C',
- "boxUr;": '\U00002559',
- "boxV;": '\U00002551',
- "boxVH;": '\U0000256C',
- "boxVL;": '\U00002563',
- "boxVR;": '\U00002560',
- "boxVh;": '\U0000256B',
- "boxVl;": '\U00002562',
- "boxVr;": '\U0000255F',
- "boxbox;": '\U000029C9',
- "boxdL;": '\U00002555',
- "boxdR;": '\U00002552',
- "boxdl;": '\U00002510',
- "boxdr;": '\U0000250C',
- "boxh;": '\U00002500',
- "boxhD;": '\U00002565',
- "boxhU;": '\U00002568',
- "boxhd;": '\U0000252C',
- "boxhu;": '\U00002534',
- "boxminus;": '\U0000229F',
- "boxplus;": '\U0000229E',
- "boxtimes;": '\U000022A0',
- "boxuL;": '\U0000255B',
- "boxuR;": '\U00002558',
- "boxul;": '\U00002518',
- "boxur;": '\U00002514',
- "boxv;": '\U00002502',
- "boxvH;": '\U0000256A',
- "boxvL;": '\U00002561',
- "boxvR;": '\U0000255E',
- "boxvh;": '\U0000253C',
- "boxvl;": '\U00002524',
- "boxvr;": '\U0000251C',
- "bprime;": '\U00002035',
- "breve;": '\U000002D8',
- "brvbar;": '\U000000A6',
- "bscr;": '\U0001D4B7',
- "bsemi;": '\U0000204F',
- "bsim;": '\U0000223D',
- "bsime;": '\U000022CD',
- "bsol;": '\U0000005C',
- "bsolb;": '\U000029C5',
- "bsolhsub;": '\U000027C8',
- "bull;": '\U00002022',
- "bullet;": '\U00002022',
- "bump;": '\U0000224E',
- "bumpE;": '\U00002AAE',
- "bumpe;": '\U0000224F',
- "bumpeq;": '\U0000224F',
- "cacute;": '\U00000107',
- "cap;": '\U00002229',
- "capand;": '\U00002A44',
- "capbrcup;": '\U00002A49',
- "capcap;": '\U00002A4B',
- "capcup;": '\U00002A47',
- "capdot;": '\U00002A40',
- "caret;": '\U00002041',
- "caron;": '\U000002C7',
- "ccaps;": '\U00002A4D',
- "ccaron;": '\U0000010D',
- "ccedil;": '\U000000E7',
- "ccirc;": '\U00000109',
- "ccups;": '\U00002A4C',
- "ccupssm;": '\U00002A50',
- "cdot;": '\U0000010B',
- "cedil;": '\U000000B8',
- "cemptyv;": '\U000029B2',
- "cent;": '\U000000A2',
- "centerdot;": '\U000000B7',
- "cfr;": '\U0001D520',
- "chcy;": '\U00000447',
- "check;": '\U00002713',
- "checkmark;": '\U00002713',
- "chi;": '\U000003C7',
- "cir;": '\U000025CB',
- "cirE;": '\U000029C3',
- "circ;": '\U000002C6',
- "circeq;": '\U00002257',
- "circlearrowleft;": '\U000021BA',
- "circlearrowright;": '\U000021BB',
- "circledR;": '\U000000AE',
- "circledS;": '\U000024C8',
- "circledast;": '\U0000229B',
- "circledcirc;": '\U0000229A',
- "circleddash;": '\U0000229D',
- "cire;": '\U00002257',
- "cirfnint;": '\U00002A10',
- "cirmid;": '\U00002AEF',
- "cirscir;": '\U000029C2',
- "clubs;": '\U00002663',
- "clubsuit;": '\U00002663',
- "colon;": '\U0000003A',
- "colone;": '\U00002254',
- "coloneq;": '\U00002254',
- "comma;": '\U0000002C',
- "commat;": '\U00000040',
- "comp;": '\U00002201',
- "compfn;": '\U00002218',
- "complement;": '\U00002201',
- "complexes;": '\U00002102',
- "cong;": '\U00002245',
- "congdot;": '\U00002A6D',
- "conint;": '\U0000222E',
- "copf;": '\U0001D554',
- "coprod;": '\U00002210',
- "copy;": '\U000000A9',
- "copysr;": '\U00002117',
- "crarr;": '\U000021B5',
- "cross;": '\U00002717',
- "cscr;": '\U0001D4B8',
- "csub;": '\U00002ACF',
- "csube;": '\U00002AD1',
- "csup;": '\U00002AD0',
- "csupe;": '\U00002AD2',
- "ctdot;": '\U000022EF',
- "cudarrl;": '\U00002938',
- "cudarrr;": '\U00002935',
- "cuepr;": '\U000022DE',
- "cuesc;": '\U000022DF',
- "cularr;": '\U000021B6',
- "cularrp;": '\U0000293D',
- "cup;": '\U0000222A',
- "cupbrcap;": '\U00002A48',
- "cupcap;": '\U00002A46',
- "cupcup;": '\U00002A4A',
- "cupdot;": '\U0000228D',
- "cupor;": '\U00002A45',
- "curarr;": '\U000021B7',
- "curarrm;": '\U0000293C',
- "curlyeqprec;": '\U000022DE',
- "curlyeqsucc;": '\U000022DF',
- "curlyvee;": '\U000022CE',
- "curlywedge;": '\U000022CF',
- "curren;": '\U000000A4',
- "curvearrowleft;": '\U000021B6',
- "curvearrowright;": '\U000021B7',
- "cuvee;": '\U000022CE',
- "cuwed;": '\U000022CF',
- "cwconint;": '\U00002232',
- "cwint;": '\U00002231',
- "cylcty;": '\U0000232D',
- "dArr;": '\U000021D3',
- "dHar;": '\U00002965',
- "dagger;": '\U00002020',
- "daleth;": '\U00002138',
- "darr;": '\U00002193',
- "dash;": '\U00002010',
- "dashv;": '\U000022A3',
- "dbkarow;": '\U0000290F',
- "dblac;": '\U000002DD',
- "dcaron;": '\U0000010F',
- "dcy;": '\U00000434',
- "dd;": '\U00002146',
- "ddagger;": '\U00002021',
- "ddarr;": '\U000021CA',
- "ddotseq;": '\U00002A77',
- "deg;": '\U000000B0',
- "delta;": '\U000003B4',
- "demptyv;": '\U000029B1',
- "dfisht;": '\U0000297F',
- "dfr;": '\U0001D521',
- "dharl;": '\U000021C3',
- "dharr;": '\U000021C2',
- "diam;": '\U000022C4',
- "diamond;": '\U000022C4',
- "diamondsuit;": '\U00002666',
- "diams;": '\U00002666',
- "die;": '\U000000A8',
- "digamma;": '\U000003DD',
- "disin;": '\U000022F2',
- "div;": '\U000000F7',
- "divide;": '\U000000F7',
- "divideontimes;": '\U000022C7',
- "divonx;": '\U000022C7',
- "djcy;": '\U00000452',
- "dlcorn;": '\U0000231E',
- "dlcrop;": '\U0000230D',
- "dollar;": '\U00000024',
- "dopf;": '\U0001D555',
- "dot;": '\U000002D9',
- "doteq;": '\U00002250',
- "doteqdot;": '\U00002251',
- "dotminus;": '\U00002238',
- "dotplus;": '\U00002214',
- "dotsquare;": '\U000022A1',
- "doublebarwedge;": '\U00002306',
- "downarrow;": '\U00002193',
- "downdownarrows;": '\U000021CA',
- "downharpoonleft;": '\U000021C3',
- "downharpoonright;": '\U000021C2',
- "drbkarow;": '\U00002910',
- "drcorn;": '\U0000231F',
- "drcrop;": '\U0000230C',
- "dscr;": '\U0001D4B9',
- "dscy;": '\U00000455',
- "dsol;": '\U000029F6',
- "dstrok;": '\U00000111',
- "dtdot;": '\U000022F1',
- "dtri;": '\U000025BF',
- "dtrif;": '\U000025BE',
- "duarr;": '\U000021F5',
- "duhar;": '\U0000296F',
- "dwangle;": '\U000029A6',
- "dzcy;": '\U0000045F',
- "dzigrarr;": '\U000027FF',
- "eDDot;": '\U00002A77',
- "eDot;": '\U00002251',
- "eacute;": '\U000000E9',
- "easter;": '\U00002A6E',
- "ecaron;": '\U0000011B',
- "ecir;": '\U00002256',
- "ecirc;": '\U000000EA',
- "ecolon;": '\U00002255',
- "ecy;": '\U0000044D',
- "edot;": '\U00000117',
- "ee;": '\U00002147',
- "efDot;": '\U00002252',
- "efr;": '\U0001D522',
- "eg;": '\U00002A9A',
- "egrave;": '\U000000E8',
- "egs;": '\U00002A96',
- "egsdot;": '\U00002A98',
- "el;": '\U00002A99',
- "elinters;": '\U000023E7',
- "ell;": '\U00002113',
- "els;": '\U00002A95',
- "elsdot;": '\U00002A97',
- "emacr;": '\U00000113',
- "empty;": '\U00002205',
- "emptyset;": '\U00002205',
- "emptyv;": '\U00002205',
- "emsp;": '\U00002003',
- "emsp13;": '\U00002004',
- "emsp14;": '\U00002005',
- "eng;": '\U0000014B',
- "ensp;": '\U00002002',
- "eogon;": '\U00000119',
- "eopf;": '\U0001D556',
- "epar;": '\U000022D5',
- "eparsl;": '\U000029E3',
- "eplus;": '\U00002A71',
- "epsi;": '\U000003B5',
- "epsilon;": '\U000003B5',
- "epsiv;": '\U000003F5',
- "eqcirc;": '\U00002256',
- "eqcolon;": '\U00002255',
- "eqsim;": '\U00002242',
- "eqslantgtr;": '\U00002A96',
- "eqslantless;": '\U00002A95',
- "equals;": '\U0000003D',
- "equest;": '\U0000225F',
- "equiv;": '\U00002261',
- "equivDD;": '\U00002A78',
- "eqvparsl;": '\U000029E5',
- "erDot;": '\U00002253',
- "erarr;": '\U00002971',
- "escr;": '\U0000212F',
- "esdot;": '\U00002250',
- "esim;": '\U00002242',
- "eta;": '\U000003B7',
- "eth;": '\U000000F0',
- "euml;": '\U000000EB',
- "euro;": '\U000020AC',
- "excl;": '\U00000021',
- "exist;": '\U00002203',
- "expectation;": '\U00002130',
- "exponentiale;": '\U00002147',
- "fallingdotseq;": '\U00002252',
- "fcy;": '\U00000444',
- "female;": '\U00002640',
- "ffilig;": '\U0000FB03',
- "fflig;": '\U0000FB00',
- "ffllig;": '\U0000FB04',
- "ffr;": '\U0001D523',
- "filig;": '\U0000FB01',
- "flat;": '\U0000266D',
- "fllig;": '\U0000FB02',
- "fltns;": '\U000025B1',
- "fnof;": '\U00000192',
- "fopf;": '\U0001D557',
- "forall;": '\U00002200',
- "fork;": '\U000022D4',
- "forkv;": '\U00002AD9',
- "fpartint;": '\U00002A0D',
- "frac12;": '\U000000BD',
- "frac13;": '\U00002153',
- "frac14;": '\U000000BC',
- "frac15;": '\U00002155',
- "frac16;": '\U00002159',
- "frac18;": '\U0000215B',
- "frac23;": '\U00002154',
- "frac25;": '\U00002156',
- "frac34;": '\U000000BE',
- "frac35;": '\U00002157',
- "frac38;": '\U0000215C',
- "frac45;": '\U00002158',
- "frac56;": '\U0000215A',
- "frac58;": '\U0000215D',
- "frac78;": '\U0000215E',
- "frasl;": '\U00002044',
- "frown;": '\U00002322',
- "fscr;": '\U0001D4BB',
- "gE;": '\U00002267',
- "gEl;": '\U00002A8C',
- "gacute;": '\U000001F5',
- "gamma;": '\U000003B3',
- "gammad;": '\U000003DD',
- "gap;": '\U00002A86',
- "gbreve;": '\U0000011F',
- "gcirc;": '\U0000011D',
- "gcy;": '\U00000433',
- "gdot;": '\U00000121',
- "ge;": '\U00002265',
- "gel;": '\U000022DB',
- "geq;": '\U00002265',
- "geqq;": '\U00002267',
- "geqslant;": '\U00002A7E',
- "ges;": '\U00002A7E',
- "gescc;": '\U00002AA9',
- "gesdot;": '\U00002A80',
- "gesdoto;": '\U00002A82',
- "gesdotol;": '\U00002A84',
- "gesles;": '\U00002A94',
- "gfr;": '\U0001D524',
- "gg;": '\U0000226B',
- "ggg;": '\U000022D9',
- "gimel;": '\U00002137',
- "gjcy;": '\U00000453',
- "gl;": '\U00002277',
- "glE;": '\U00002A92',
- "gla;": '\U00002AA5',
- "glj;": '\U00002AA4',
- "gnE;": '\U00002269',
- "gnap;": '\U00002A8A',
- "gnapprox;": '\U00002A8A',
- "gne;": '\U00002A88',
- "gneq;": '\U00002A88',
- "gneqq;": '\U00002269',
- "gnsim;": '\U000022E7',
- "gopf;": '\U0001D558',
- "grave;": '\U00000060',
- "gscr;": '\U0000210A',
- "gsim;": '\U00002273',
- "gsime;": '\U00002A8E',
- "gsiml;": '\U00002A90',
- "gt;": '\U0000003E',
- "gtcc;": '\U00002AA7',
- "gtcir;": '\U00002A7A',
- "gtdot;": '\U000022D7',
- "gtlPar;": '\U00002995',
- "gtquest;": '\U00002A7C',
- "gtrapprox;": '\U00002A86',
- "gtrarr;": '\U00002978',
- "gtrdot;": '\U000022D7',
- "gtreqless;": '\U000022DB',
- "gtreqqless;": '\U00002A8C',
- "gtrless;": '\U00002277',
- "gtrsim;": '\U00002273',
- "hArr;": '\U000021D4',
- "hairsp;": '\U0000200A',
- "half;": '\U000000BD',
- "hamilt;": '\U0000210B',
- "hardcy;": '\U0000044A',
- "harr;": '\U00002194',
- "harrcir;": '\U00002948',
- "harrw;": '\U000021AD',
- "hbar;": '\U0000210F',
- "hcirc;": '\U00000125',
- "hearts;": '\U00002665',
- "heartsuit;": '\U00002665',
- "hellip;": '\U00002026',
- "hercon;": '\U000022B9',
- "hfr;": '\U0001D525',
- "hksearow;": '\U00002925',
- "hkswarow;": '\U00002926',
- "hoarr;": '\U000021FF',
- "homtht;": '\U0000223B',
- "hookleftarrow;": '\U000021A9',
- "hookrightarrow;": '\U000021AA',
- "hopf;": '\U0001D559',
- "horbar;": '\U00002015',
- "hscr;": '\U0001D4BD',
- "hslash;": '\U0000210F',
- "hstrok;": '\U00000127',
- "hybull;": '\U00002043',
- "hyphen;": '\U00002010',
- "iacute;": '\U000000ED',
- "ic;": '\U00002063',
- "icirc;": '\U000000EE',
- "icy;": '\U00000438',
- "iecy;": '\U00000435',
- "iexcl;": '\U000000A1',
- "iff;": '\U000021D4',
- "ifr;": '\U0001D526',
- "igrave;": '\U000000EC',
- "ii;": '\U00002148',
- "iiiint;": '\U00002A0C',
- "iiint;": '\U0000222D',
- "iinfin;": '\U000029DC',
- "iiota;": '\U00002129',
- "ijlig;": '\U00000133',
- "imacr;": '\U0000012B',
- "image;": '\U00002111',
- "imagline;": '\U00002110',
- "imagpart;": '\U00002111',
- "imath;": '\U00000131',
- "imof;": '\U000022B7',
- "imped;": '\U000001B5',
- "in;": '\U00002208',
- "incare;": '\U00002105',
- "infin;": '\U0000221E',
- "infintie;": '\U000029DD',
- "inodot;": '\U00000131',
- "int;": '\U0000222B',
- "intcal;": '\U000022BA',
- "integers;": '\U00002124',
- "intercal;": '\U000022BA',
- "intlarhk;": '\U00002A17',
- "intprod;": '\U00002A3C',
- "iocy;": '\U00000451',
- "iogon;": '\U0000012F',
- "iopf;": '\U0001D55A',
- "iota;": '\U000003B9',
- "iprod;": '\U00002A3C',
- "iquest;": '\U000000BF',
- "iscr;": '\U0001D4BE',
- "isin;": '\U00002208',
- "isinE;": '\U000022F9',
- "isindot;": '\U000022F5',
- "isins;": '\U000022F4',
- "isinsv;": '\U000022F3',
- "isinv;": '\U00002208',
- "it;": '\U00002062',
- "itilde;": '\U00000129',
- "iukcy;": '\U00000456',
- "iuml;": '\U000000EF',
- "jcirc;": '\U00000135',
- "jcy;": '\U00000439',
- "jfr;": '\U0001D527',
- "jmath;": '\U00000237',
- "jopf;": '\U0001D55B',
- "jscr;": '\U0001D4BF',
- "jsercy;": '\U00000458',
- "jukcy;": '\U00000454',
- "kappa;": '\U000003BA',
- "kappav;": '\U000003F0',
- "kcedil;": '\U00000137',
- "kcy;": '\U0000043A',
- "kfr;": '\U0001D528',
- "kgreen;": '\U00000138',
- "khcy;": '\U00000445',
- "kjcy;": '\U0000045C',
- "kopf;": '\U0001D55C',
- "kscr;": '\U0001D4C0',
- "lAarr;": '\U000021DA',
- "lArr;": '\U000021D0',
- "lAtail;": '\U0000291B',
- "lBarr;": '\U0000290E',
- "lE;": '\U00002266',
- "lEg;": '\U00002A8B',
- "lHar;": '\U00002962',
- "lacute;": '\U0000013A',
- "laemptyv;": '\U000029B4',
- "lagran;": '\U00002112',
- "lambda;": '\U000003BB',
- "lang;": '\U000027E8',
- "langd;": '\U00002991',
- "langle;": '\U000027E8',
- "lap;": '\U00002A85',
- "laquo;": '\U000000AB',
- "larr;": '\U00002190',
- "larrb;": '\U000021E4',
- "larrbfs;": '\U0000291F',
- "larrfs;": '\U0000291D',
- "larrhk;": '\U000021A9',
- "larrlp;": '\U000021AB',
- "larrpl;": '\U00002939',
- "larrsim;": '\U00002973',
- "larrtl;": '\U000021A2',
- "lat;": '\U00002AAB',
- "latail;": '\U00002919',
- "late;": '\U00002AAD',
- "lbarr;": '\U0000290C',
- "lbbrk;": '\U00002772',
- "lbrace;": '\U0000007B',
- "lbrack;": '\U0000005B',
- "lbrke;": '\U0000298B',
- "lbrksld;": '\U0000298F',
- "lbrkslu;": '\U0000298D',
- "lcaron;": '\U0000013E',
- "lcedil;": '\U0000013C',
- "lceil;": '\U00002308',
- "lcub;": '\U0000007B',
- "lcy;": '\U0000043B',
- "ldca;": '\U00002936',
- "ldquo;": '\U0000201C',
- "ldquor;": '\U0000201E',
- "ldrdhar;": '\U00002967',
- "ldrushar;": '\U0000294B',
- "ldsh;": '\U000021B2',
- "le;": '\U00002264',
- "leftarrow;": '\U00002190',
- "leftarrowtail;": '\U000021A2',
- "leftharpoondown;": '\U000021BD',
- "leftharpoonup;": '\U000021BC',
- "leftleftarrows;": '\U000021C7',
- "leftrightarrow;": '\U00002194',
- "leftrightarrows;": '\U000021C6',
- "leftrightharpoons;": '\U000021CB',
- "leftrightsquigarrow;": '\U000021AD',
- "leftthreetimes;": '\U000022CB',
- "leg;": '\U000022DA',
- "leq;": '\U00002264',
- "leqq;": '\U00002266',
- "leqslant;": '\U00002A7D',
- "les;": '\U00002A7D',
- "lescc;": '\U00002AA8',
- "lesdot;": '\U00002A7F',
- "lesdoto;": '\U00002A81',
- "lesdotor;": '\U00002A83',
- "lesges;": '\U00002A93',
- "lessapprox;": '\U00002A85',
- "lessdot;": '\U000022D6',
- "lesseqgtr;": '\U000022DA',
- "lesseqqgtr;": '\U00002A8B',
- "lessgtr;": '\U00002276',
- "lesssim;": '\U00002272',
- "lfisht;": '\U0000297C',
- "lfloor;": '\U0000230A',
- "lfr;": '\U0001D529',
- "lg;": '\U00002276',
- "lgE;": '\U00002A91',
- "lhard;": '\U000021BD',
- "lharu;": '\U000021BC',
- "lharul;": '\U0000296A',
- "lhblk;": '\U00002584',
- "ljcy;": '\U00000459',
- "ll;": '\U0000226A',
- "llarr;": '\U000021C7',
- "llcorner;": '\U0000231E',
- "llhard;": '\U0000296B',
- "lltri;": '\U000025FA',
- "lmidot;": '\U00000140',
- "lmoust;": '\U000023B0',
- "lmoustache;": '\U000023B0',
- "lnE;": '\U00002268',
- "lnap;": '\U00002A89',
- "lnapprox;": '\U00002A89',
- "lne;": '\U00002A87',
- "lneq;": '\U00002A87',
- "lneqq;": '\U00002268',
- "lnsim;": '\U000022E6',
- "loang;": '\U000027EC',
- "loarr;": '\U000021FD',
- "lobrk;": '\U000027E6',
- "longleftarrow;": '\U000027F5',
- "longleftrightarrow;": '\U000027F7',
- "longmapsto;": '\U000027FC',
- "longrightarrow;": '\U000027F6',
- "looparrowleft;": '\U000021AB',
- "looparrowright;": '\U000021AC',
- "lopar;": '\U00002985',
- "lopf;": '\U0001D55D',
- "loplus;": '\U00002A2D',
- "lotimes;": '\U00002A34',
- "lowast;": '\U00002217',
- "lowbar;": '\U0000005F',
- "loz;": '\U000025CA',
- "lozenge;": '\U000025CA',
- "lozf;": '\U000029EB',
- "lpar;": '\U00000028',
- "lparlt;": '\U00002993',
- "lrarr;": '\U000021C6',
- "lrcorner;": '\U0000231F',
- "lrhar;": '\U000021CB',
- "lrhard;": '\U0000296D',
- "lrm;": '\U0000200E',
- "lrtri;": '\U000022BF',
- "lsaquo;": '\U00002039',
- "lscr;": '\U0001D4C1',
- "lsh;": '\U000021B0',
- "lsim;": '\U00002272',
- "lsime;": '\U00002A8D',
- "lsimg;": '\U00002A8F',
- "lsqb;": '\U0000005B',
- "lsquo;": '\U00002018',
- "lsquor;": '\U0000201A',
- "lstrok;": '\U00000142',
- "lt;": '\U0000003C',
- "ltcc;": '\U00002AA6',
- "ltcir;": '\U00002A79',
- "ltdot;": '\U000022D6',
- "lthree;": '\U000022CB',
- "ltimes;": '\U000022C9',
- "ltlarr;": '\U00002976',
- "ltquest;": '\U00002A7B',
- "ltrPar;": '\U00002996',
- "ltri;": '\U000025C3',
- "ltrie;": '\U000022B4',
- "ltrif;": '\U000025C2',
- "lurdshar;": '\U0000294A',
- "luruhar;": '\U00002966',
- "mDDot;": '\U0000223A',
- "macr;": '\U000000AF',
- "male;": '\U00002642',
- "malt;": '\U00002720',
- "maltese;": '\U00002720',
- "map;": '\U000021A6',
- "mapsto;": '\U000021A6',
- "mapstodown;": '\U000021A7',
- "mapstoleft;": '\U000021A4',
- "mapstoup;": '\U000021A5',
- "marker;": '\U000025AE',
- "mcomma;": '\U00002A29',
- "mcy;": '\U0000043C',
- "mdash;": '\U00002014',
- "measuredangle;": '\U00002221',
- "mfr;": '\U0001D52A',
- "mho;": '\U00002127',
- "micro;": '\U000000B5',
- "mid;": '\U00002223',
- "midast;": '\U0000002A',
- "midcir;": '\U00002AF0',
- "middot;": '\U000000B7',
- "minus;": '\U00002212',
- "minusb;": '\U0000229F',
- "minusd;": '\U00002238',
- "minusdu;": '\U00002A2A',
- "mlcp;": '\U00002ADB',
- "mldr;": '\U00002026',
- "mnplus;": '\U00002213',
- "models;": '\U000022A7',
- "mopf;": '\U0001D55E',
- "mp;": '\U00002213',
- "mscr;": '\U0001D4C2',
- "mstpos;": '\U0000223E',
- "mu;": '\U000003BC',
- "multimap;": '\U000022B8',
- "mumap;": '\U000022B8',
- "nLeftarrow;": '\U000021CD',
- "nLeftrightarrow;": '\U000021CE',
- "nRightarrow;": '\U000021CF',
- "nVDash;": '\U000022AF',
- "nVdash;": '\U000022AE',
- "nabla;": '\U00002207',
- "nacute;": '\U00000144',
- "nap;": '\U00002249',
- "napos;": '\U00000149',
- "napprox;": '\U00002249',
- "natur;": '\U0000266E',
- "natural;": '\U0000266E',
- "naturals;": '\U00002115',
- "nbsp;": '\U000000A0',
- "ncap;": '\U00002A43',
- "ncaron;": '\U00000148',
- "ncedil;": '\U00000146',
- "ncong;": '\U00002247',
- "ncup;": '\U00002A42',
- "ncy;": '\U0000043D',
- "ndash;": '\U00002013',
- "ne;": '\U00002260',
- "neArr;": '\U000021D7',
- "nearhk;": '\U00002924',
- "nearr;": '\U00002197',
- "nearrow;": '\U00002197',
- "nequiv;": '\U00002262',
- "nesear;": '\U00002928',
- "nexist;": '\U00002204',
- "nexists;": '\U00002204',
- "nfr;": '\U0001D52B',
- "nge;": '\U00002271',
- "ngeq;": '\U00002271',
- "ngsim;": '\U00002275',
- "ngt;": '\U0000226F',
- "ngtr;": '\U0000226F',
- "nhArr;": '\U000021CE',
- "nharr;": '\U000021AE',
- "nhpar;": '\U00002AF2',
- "ni;": '\U0000220B',
- "nis;": '\U000022FC',
- "nisd;": '\U000022FA',
- "niv;": '\U0000220B',
- "njcy;": '\U0000045A',
- "nlArr;": '\U000021CD',
- "nlarr;": '\U0000219A',
- "nldr;": '\U00002025',
- "nle;": '\U00002270',
- "nleftarrow;": '\U0000219A',
- "nleftrightarrow;": '\U000021AE',
- "nleq;": '\U00002270',
- "nless;": '\U0000226E',
- "nlsim;": '\U00002274',
- "nlt;": '\U0000226E',
- "nltri;": '\U000022EA',
- "nltrie;": '\U000022EC',
- "nmid;": '\U00002224',
- "nopf;": '\U0001D55F',
- "not;": '\U000000AC',
- "notin;": '\U00002209',
- "notinva;": '\U00002209',
- "notinvb;": '\U000022F7',
- "notinvc;": '\U000022F6',
- "notni;": '\U0000220C',
- "notniva;": '\U0000220C',
- "notnivb;": '\U000022FE',
- "notnivc;": '\U000022FD',
- "npar;": '\U00002226',
- "nparallel;": '\U00002226',
- "npolint;": '\U00002A14',
- "npr;": '\U00002280',
- "nprcue;": '\U000022E0',
- "nprec;": '\U00002280',
- "nrArr;": '\U000021CF',
- "nrarr;": '\U0000219B',
- "nrightarrow;": '\U0000219B',
- "nrtri;": '\U000022EB',
- "nrtrie;": '\U000022ED',
- "nsc;": '\U00002281',
- "nsccue;": '\U000022E1',
- "nscr;": '\U0001D4C3',
- "nshortmid;": '\U00002224',
- "nshortparallel;": '\U00002226',
- "nsim;": '\U00002241',
- "nsime;": '\U00002244',
- "nsimeq;": '\U00002244',
- "nsmid;": '\U00002224',
- "nspar;": '\U00002226',
- "nsqsube;": '\U000022E2',
- "nsqsupe;": '\U000022E3',
- "nsub;": '\U00002284',
- "nsube;": '\U00002288',
- "nsubseteq;": '\U00002288',
- "nsucc;": '\U00002281',
- "nsup;": '\U00002285',
- "nsupe;": '\U00002289',
- "nsupseteq;": '\U00002289',
- "ntgl;": '\U00002279',
- "ntilde;": '\U000000F1',
- "ntlg;": '\U00002278',
- "ntriangleleft;": '\U000022EA',
- "ntrianglelefteq;": '\U000022EC',
- "ntriangleright;": '\U000022EB',
- "ntrianglerighteq;": '\U000022ED',
- "nu;": '\U000003BD',
- "num;": '\U00000023',
- "numero;": '\U00002116',
- "numsp;": '\U00002007',
- "nvDash;": '\U000022AD',
- "nvHarr;": '\U00002904',
- "nvdash;": '\U000022AC',
- "nvinfin;": '\U000029DE',
- "nvlArr;": '\U00002902',
- "nvrArr;": '\U00002903',
- "nwArr;": '\U000021D6',
- "nwarhk;": '\U00002923',
- "nwarr;": '\U00002196',
- "nwarrow;": '\U00002196',
- "nwnear;": '\U00002927',
- "oS;": '\U000024C8',
- "oacute;": '\U000000F3',
- "oast;": '\U0000229B',
- "ocir;": '\U0000229A',
- "ocirc;": '\U000000F4',
- "ocy;": '\U0000043E',
- "odash;": '\U0000229D',
- "odblac;": '\U00000151',
- "odiv;": '\U00002A38',
- "odot;": '\U00002299',
- "odsold;": '\U000029BC',
- "oelig;": '\U00000153',
- "ofcir;": '\U000029BF',
- "ofr;": '\U0001D52C',
- "ogon;": '\U000002DB',
- "ograve;": '\U000000F2',
- "ogt;": '\U000029C1',
- "ohbar;": '\U000029B5',
- "ohm;": '\U000003A9',
- "oint;": '\U0000222E',
- "olarr;": '\U000021BA',
- "olcir;": '\U000029BE',
- "olcross;": '\U000029BB',
- "oline;": '\U0000203E',
- "olt;": '\U000029C0',
- "omacr;": '\U0000014D',
- "omega;": '\U000003C9',
- "omicron;": '\U000003BF',
- "omid;": '\U000029B6',
- "ominus;": '\U00002296',
- "oopf;": '\U0001D560',
- "opar;": '\U000029B7',
- "operp;": '\U000029B9',
- "oplus;": '\U00002295',
- "or;": '\U00002228',
- "orarr;": '\U000021BB',
- "ord;": '\U00002A5D',
- "order;": '\U00002134',
- "orderof;": '\U00002134',
- "ordf;": '\U000000AA',
- "ordm;": '\U000000BA',
- "origof;": '\U000022B6',
- "oror;": '\U00002A56',
- "orslope;": '\U00002A57',
- "orv;": '\U00002A5B',
- "oscr;": '\U00002134',
- "oslash;": '\U000000F8',
- "osol;": '\U00002298',
- "otilde;": '\U000000F5',
- "otimes;": '\U00002297',
- "otimesas;": '\U00002A36',
- "ouml;": '\U000000F6',
- "ovbar;": '\U0000233D',
- "par;": '\U00002225',
- "para;": '\U000000B6',
- "parallel;": '\U00002225',
- "parsim;": '\U00002AF3',
- "parsl;": '\U00002AFD',
- "part;": '\U00002202',
- "pcy;": '\U0000043F',
- "percnt;": '\U00000025',
- "period;": '\U0000002E',
- "permil;": '\U00002030',
- "perp;": '\U000022A5',
- "pertenk;": '\U00002031',
- "pfr;": '\U0001D52D',
- "phi;": '\U000003C6',
- "phiv;": '\U000003D5',
- "phmmat;": '\U00002133',
- "phone;": '\U0000260E',
- "pi;": '\U000003C0',
- "pitchfork;": '\U000022D4',
- "piv;": '\U000003D6',
- "planck;": '\U0000210F',
- "planckh;": '\U0000210E',
- "plankv;": '\U0000210F',
- "plus;": '\U0000002B',
- "plusacir;": '\U00002A23',
- "plusb;": '\U0000229E',
- "pluscir;": '\U00002A22',
- "plusdo;": '\U00002214',
- "plusdu;": '\U00002A25',
- "pluse;": '\U00002A72',
- "plusmn;": '\U000000B1',
- "plussim;": '\U00002A26',
- "plustwo;": '\U00002A27',
- "pm;": '\U000000B1',
- "pointint;": '\U00002A15',
- "popf;": '\U0001D561',
- "pound;": '\U000000A3',
- "pr;": '\U0000227A',
- "prE;": '\U00002AB3',
- "prap;": '\U00002AB7',
- "prcue;": '\U0000227C',
- "pre;": '\U00002AAF',
- "prec;": '\U0000227A',
- "precapprox;": '\U00002AB7',
- "preccurlyeq;": '\U0000227C',
- "preceq;": '\U00002AAF',
- "precnapprox;": '\U00002AB9',
- "precneqq;": '\U00002AB5',
- "precnsim;": '\U000022E8',
- "precsim;": '\U0000227E',
- "prime;": '\U00002032',
- "primes;": '\U00002119',
- "prnE;": '\U00002AB5',
- "prnap;": '\U00002AB9',
- "prnsim;": '\U000022E8',
- "prod;": '\U0000220F',
- "profalar;": '\U0000232E',
- "profline;": '\U00002312',
- "profsurf;": '\U00002313',
- "prop;": '\U0000221D',
- "propto;": '\U0000221D',
- "prsim;": '\U0000227E',
- "prurel;": '\U000022B0',
- "pscr;": '\U0001D4C5',
- "psi;": '\U000003C8',
- "puncsp;": '\U00002008',
- "qfr;": '\U0001D52E',
- "qint;": '\U00002A0C',
- "qopf;": '\U0001D562',
- "qprime;": '\U00002057',
- "qscr;": '\U0001D4C6',
- "quaternions;": '\U0000210D',
- "quatint;": '\U00002A16',
- "quest;": '\U0000003F',
- "questeq;": '\U0000225F',
- "quot;": '\U00000022',
- "rAarr;": '\U000021DB',
- "rArr;": '\U000021D2',
- "rAtail;": '\U0000291C',
- "rBarr;": '\U0000290F',
- "rHar;": '\U00002964',
- "racute;": '\U00000155',
- "radic;": '\U0000221A',
- "raemptyv;": '\U000029B3',
- "rang;": '\U000027E9',
- "rangd;": '\U00002992',
- "range;": '\U000029A5',
- "rangle;": '\U000027E9',
- "raquo;": '\U000000BB',
- "rarr;": '\U00002192',
- "rarrap;": '\U00002975',
- "rarrb;": '\U000021E5',
- "rarrbfs;": '\U00002920',
- "rarrc;": '\U00002933',
- "rarrfs;": '\U0000291E',
- "rarrhk;": '\U000021AA',
- "rarrlp;": '\U000021AC',
- "rarrpl;": '\U00002945',
- "rarrsim;": '\U00002974',
- "rarrtl;": '\U000021A3',
- "rarrw;": '\U0000219D',
- "ratail;": '\U0000291A',
- "ratio;": '\U00002236',
- "rationals;": '\U0000211A',
- "rbarr;": '\U0000290D',
- "rbbrk;": '\U00002773',
- "rbrace;": '\U0000007D',
- "rbrack;": '\U0000005D',
- "rbrke;": '\U0000298C',
- "rbrksld;": '\U0000298E',
- "rbrkslu;": '\U00002990',
- "rcaron;": '\U00000159',
- "rcedil;": '\U00000157',
- "rceil;": '\U00002309',
- "rcub;": '\U0000007D',
- "rcy;": '\U00000440',
- "rdca;": '\U00002937',
- "rdldhar;": '\U00002969',
- "rdquo;": '\U0000201D',
- "rdquor;": '\U0000201D',
- "rdsh;": '\U000021B3',
- "real;": '\U0000211C',
- "realine;": '\U0000211B',
- "realpart;": '\U0000211C',
- "reals;": '\U0000211D',
- "rect;": '\U000025AD',
- "reg;": '\U000000AE',
- "rfisht;": '\U0000297D',
- "rfloor;": '\U0000230B',
- "rfr;": '\U0001D52F',
- "rhard;": '\U000021C1',
- "rharu;": '\U000021C0',
- "rharul;": '\U0000296C',
- "rho;": '\U000003C1',
- "rhov;": '\U000003F1',
- "rightarrow;": '\U00002192',
- "rightarrowtail;": '\U000021A3',
- "rightharpoondown;": '\U000021C1',
- "rightharpoonup;": '\U000021C0',
- "rightleftarrows;": '\U000021C4',
- "rightleftharpoons;": '\U000021CC',
- "rightrightarrows;": '\U000021C9',
- "rightsquigarrow;": '\U0000219D',
- "rightthreetimes;": '\U000022CC',
- "ring;": '\U000002DA',
- "risingdotseq;": '\U00002253',
- "rlarr;": '\U000021C4',
- "rlhar;": '\U000021CC',
- "rlm;": '\U0000200F',
- "rmoust;": '\U000023B1',
- "rmoustache;": '\U000023B1',
- "rnmid;": '\U00002AEE',
- "roang;": '\U000027ED',
- "roarr;": '\U000021FE',
- "robrk;": '\U000027E7',
- "ropar;": '\U00002986',
- "ropf;": '\U0001D563',
- "roplus;": '\U00002A2E',
- "rotimes;": '\U00002A35',
- "rpar;": '\U00000029',
- "rpargt;": '\U00002994',
- "rppolint;": '\U00002A12',
- "rrarr;": '\U000021C9',
- "rsaquo;": '\U0000203A',
- "rscr;": '\U0001D4C7',
- "rsh;": '\U000021B1',
- "rsqb;": '\U0000005D',
- "rsquo;": '\U00002019',
- "rsquor;": '\U00002019',
- "rthree;": '\U000022CC',
- "rtimes;": '\U000022CA',
- "rtri;": '\U000025B9',
- "rtrie;": '\U000022B5',
- "rtrif;": '\U000025B8',
- "rtriltri;": '\U000029CE',
- "ruluhar;": '\U00002968',
- "rx;": '\U0000211E',
- "sacute;": '\U0000015B',
- "sbquo;": '\U0000201A',
- "sc;": '\U0000227B',
- "scE;": '\U00002AB4',
- "scap;": '\U00002AB8',
- "scaron;": '\U00000161',
- "sccue;": '\U0000227D',
- "sce;": '\U00002AB0',
- "scedil;": '\U0000015F',
- "scirc;": '\U0000015D',
- "scnE;": '\U00002AB6',
- "scnap;": '\U00002ABA',
- "scnsim;": '\U000022E9',
- "scpolint;": '\U00002A13',
- "scsim;": '\U0000227F',
- "scy;": '\U00000441',
- "sdot;": '\U000022C5',
- "sdotb;": '\U000022A1',
- "sdote;": '\U00002A66',
- "seArr;": '\U000021D8',
- "searhk;": '\U00002925',
- "searr;": '\U00002198',
- "searrow;": '\U00002198',
- "sect;": '\U000000A7',
- "semi;": '\U0000003B',
- "seswar;": '\U00002929',
- "setminus;": '\U00002216',
- "setmn;": '\U00002216',
- "sext;": '\U00002736',
- "sfr;": '\U0001D530',
- "sfrown;": '\U00002322',
- "sharp;": '\U0000266F',
- "shchcy;": '\U00000449',
- "shcy;": '\U00000448',
- "shortmid;": '\U00002223',
- "shortparallel;": '\U00002225',
- "shy;": '\U000000AD',
- "sigma;": '\U000003C3',
- "sigmaf;": '\U000003C2',
- "sigmav;": '\U000003C2',
- "sim;": '\U0000223C',
- "simdot;": '\U00002A6A',
- "sime;": '\U00002243',
- "simeq;": '\U00002243',
- "simg;": '\U00002A9E',
- "simgE;": '\U00002AA0',
- "siml;": '\U00002A9D',
- "simlE;": '\U00002A9F',
- "simne;": '\U00002246',
- "simplus;": '\U00002A24',
- "simrarr;": '\U00002972',
- "slarr;": '\U00002190',
- "smallsetminus;": '\U00002216',
- "smashp;": '\U00002A33',
- "smeparsl;": '\U000029E4',
- "smid;": '\U00002223',
- "smile;": '\U00002323',
- "smt;": '\U00002AAA',
- "smte;": '\U00002AAC',
- "softcy;": '\U0000044C',
- "sol;": '\U0000002F',
- "solb;": '\U000029C4',
- "solbar;": '\U0000233F',
- "sopf;": '\U0001D564',
- "spades;": '\U00002660',
- "spadesuit;": '\U00002660',
- "spar;": '\U00002225',
- "sqcap;": '\U00002293',
- "sqcup;": '\U00002294',
- "sqsub;": '\U0000228F',
- "sqsube;": '\U00002291',
- "sqsubset;": '\U0000228F',
- "sqsubseteq;": '\U00002291',
- "sqsup;": '\U00002290',
- "sqsupe;": '\U00002292',
- "sqsupset;": '\U00002290',
- "sqsupseteq;": '\U00002292',
- "squ;": '\U000025A1',
- "square;": '\U000025A1',
- "squarf;": '\U000025AA',
- "squf;": '\U000025AA',
- "srarr;": '\U00002192',
- "sscr;": '\U0001D4C8',
- "ssetmn;": '\U00002216',
- "ssmile;": '\U00002323',
- "sstarf;": '\U000022C6',
- "star;": '\U00002606',
- "starf;": '\U00002605',
- "straightepsilon;": '\U000003F5',
- "straightphi;": '\U000003D5',
- "strns;": '\U000000AF',
- "sub;": '\U00002282',
- "subE;": '\U00002AC5',
- "subdot;": '\U00002ABD',
- "sube;": '\U00002286',
- "subedot;": '\U00002AC3',
- "submult;": '\U00002AC1',
- "subnE;": '\U00002ACB',
- "subne;": '\U0000228A',
- "subplus;": '\U00002ABF',
- "subrarr;": '\U00002979',
- "subset;": '\U00002282',
- "subseteq;": '\U00002286',
- "subseteqq;": '\U00002AC5',
- "subsetneq;": '\U0000228A',
- "subsetneqq;": '\U00002ACB',
- "subsim;": '\U00002AC7',
- "subsub;": '\U00002AD5',
- "subsup;": '\U00002AD3',
- "succ;": '\U0000227B',
- "succapprox;": '\U00002AB8',
- "succcurlyeq;": '\U0000227D',
- "succeq;": '\U00002AB0',
- "succnapprox;": '\U00002ABA',
- "succneqq;": '\U00002AB6',
- "succnsim;": '\U000022E9',
- "succsim;": '\U0000227F',
- "sum;": '\U00002211',
- "sung;": '\U0000266A',
- "sup;": '\U00002283',
- "sup1;": '\U000000B9',
- "sup2;": '\U000000B2',
- "sup3;": '\U000000B3',
- "supE;": '\U00002AC6',
- "supdot;": '\U00002ABE',
- "supdsub;": '\U00002AD8',
- "supe;": '\U00002287',
- "supedot;": '\U00002AC4',
- "suphsol;": '\U000027C9',
- "suphsub;": '\U00002AD7',
- "suplarr;": '\U0000297B',
- "supmult;": '\U00002AC2',
- "supnE;": '\U00002ACC',
- "supne;": '\U0000228B',
- "supplus;": '\U00002AC0',
- "supset;": '\U00002283',
- "supseteq;": '\U00002287',
- "supseteqq;": '\U00002AC6',
- "supsetneq;": '\U0000228B',
- "supsetneqq;": '\U00002ACC',
- "supsim;": '\U00002AC8',
- "supsub;": '\U00002AD4',
- "supsup;": '\U00002AD6',
- "swArr;": '\U000021D9',
- "swarhk;": '\U00002926',
- "swarr;": '\U00002199',
- "swarrow;": '\U00002199',
- "swnwar;": '\U0000292A',
- "szlig;": '\U000000DF',
- "target;": '\U00002316',
- "tau;": '\U000003C4',
- "tbrk;": '\U000023B4',
- "tcaron;": '\U00000165',
- "tcedil;": '\U00000163',
- "tcy;": '\U00000442',
- "tdot;": '\U000020DB',
- "telrec;": '\U00002315',
- "tfr;": '\U0001D531',
- "there4;": '\U00002234',
- "therefore;": '\U00002234',
- "theta;": '\U000003B8',
- "thetasym;": '\U000003D1',
- "thetav;": '\U000003D1',
- "thickapprox;": '\U00002248',
- "thicksim;": '\U0000223C',
- "thinsp;": '\U00002009',
- "thkap;": '\U00002248',
- "thksim;": '\U0000223C',
- "thorn;": '\U000000FE',
- "tilde;": '\U000002DC',
- "times;": '\U000000D7',
- "timesb;": '\U000022A0',
- "timesbar;": '\U00002A31',
- "timesd;": '\U00002A30',
- "tint;": '\U0000222D',
- "toea;": '\U00002928',
- "top;": '\U000022A4',
- "topbot;": '\U00002336',
- "topcir;": '\U00002AF1',
- "topf;": '\U0001D565',
- "topfork;": '\U00002ADA',
- "tosa;": '\U00002929',
- "tprime;": '\U00002034',
- "trade;": '\U00002122',
- "triangle;": '\U000025B5',
- "triangledown;": '\U000025BF',
- "triangleleft;": '\U000025C3',
- "trianglelefteq;": '\U000022B4',
- "triangleq;": '\U0000225C',
- "triangleright;": '\U000025B9',
- "trianglerighteq;": '\U000022B5',
- "tridot;": '\U000025EC',
- "trie;": '\U0000225C',
- "triminus;": '\U00002A3A',
- "triplus;": '\U00002A39',
- "trisb;": '\U000029CD',
- "tritime;": '\U00002A3B',
- "trpezium;": '\U000023E2',
- "tscr;": '\U0001D4C9',
- "tscy;": '\U00000446',
- "tshcy;": '\U0000045B',
- "tstrok;": '\U00000167',
- "twixt;": '\U0000226C',
- "twoheadleftarrow;": '\U0000219E',
- "twoheadrightarrow;": '\U000021A0',
- "uArr;": '\U000021D1',
- "uHar;": '\U00002963',
- "uacute;": '\U000000FA',
- "uarr;": '\U00002191',
- "ubrcy;": '\U0000045E',
- "ubreve;": '\U0000016D',
- "ucirc;": '\U000000FB',
- "ucy;": '\U00000443',
- "udarr;": '\U000021C5',
- "udblac;": '\U00000171',
- "udhar;": '\U0000296E',
- "ufisht;": '\U0000297E',
- "ufr;": '\U0001D532',
- "ugrave;": '\U000000F9',
- "uharl;": '\U000021BF',
- "uharr;": '\U000021BE',
- "uhblk;": '\U00002580',
- "ulcorn;": '\U0000231C',
- "ulcorner;": '\U0000231C',
- "ulcrop;": '\U0000230F',
- "ultri;": '\U000025F8',
- "umacr;": '\U0000016B',
- "uml;": '\U000000A8',
- "uogon;": '\U00000173',
- "uopf;": '\U0001D566',
- "uparrow;": '\U00002191',
- "updownarrow;": '\U00002195',
- "upharpoonleft;": '\U000021BF',
- "upharpoonright;": '\U000021BE',
- "uplus;": '\U0000228E',
- "upsi;": '\U000003C5',
- "upsih;": '\U000003D2',
- "upsilon;": '\U000003C5',
- "upuparrows;": '\U000021C8',
- "urcorn;": '\U0000231D',
- "urcorner;": '\U0000231D',
- "urcrop;": '\U0000230E',
- "uring;": '\U0000016F',
- "urtri;": '\U000025F9',
- "uscr;": '\U0001D4CA',
- "utdot;": '\U000022F0',
- "utilde;": '\U00000169',
- "utri;": '\U000025B5',
- "utrif;": '\U000025B4',
- "uuarr;": '\U000021C8',
- "uuml;": '\U000000FC',
- "uwangle;": '\U000029A7',
- "vArr;": '\U000021D5',
- "vBar;": '\U00002AE8',
- "vBarv;": '\U00002AE9',
- "vDash;": '\U000022A8',
- "vangrt;": '\U0000299C',
- "varepsilon;": '\U000003F5',
- "varkappa;": '\U000003F0',
- "varnothing;": '\U00002205',
- "varphi;": '\U000003D5',
- "varpi;": '\U000003D6',
- "varpropto;": '\U0000221D',
- "varr;": '\U00002195',
- "varrho;": '\U000003F1',
- "varsigma;": '\U000003C2',
- "vartheta;": '\U000003D1',
- "vartriangleleft;": '\U000022B2',
- "vartriangleright;": '\U000022B3',
- "vcy;": '\U00000432',
- "vdash;": '\U000022A2',
- "vee;": '\U00002228',
- "veebar;": '\U000022BB',
- "veeeq;": '\U0000225A',
- "vellip;": '\U000022EE',
- "verbar;": '\U0000007C',
- "vert;": '\U0000007C',
- "vfr;": '\U0001D533',
- "vltri;": '\U000022B2',
- "vopf;": '\U0001D567',
- "vprop;": '\U0000221D',
- "vrtri;": '\U000022B3',
- "vscr;": '\U0001D4CB',
- "vzigzag;": '\U0000299A',
- "wcirc;": '\U00000175',
- "wedbar;": '\U00002A5F',
- "wedge;": '\U00002227',
- "wedgeq;": '\U00002259',
- "weierp;": '\U00002118',
- "wfr;": '\U0001D534',
- "wopf;": '\U0001D568',
- "wp;": '\U00002118',
- "wr;": '\U00002240',
- "wreath;": '\U00002240',
- "wscr;": '\U0001D4CC',
- "xcap;": '\U000022C2',
- "xcirc;": '\U000025EF',
- "xcup;": '\U000022C3',
- "xdtri;": '\U000025BD',
- "xfr;": '\U0001D535',
- "xhArr;": '\U000027FA',
- "xharr;": '\U000027F7',
- "xi;": '\U000003BE',
- "xlArr;": '\U000027F8',
- "xlarr;": '\U000027F5',
- "xmap;": '\U000027FC',
- "xnis;": '\U000022FB',
- "xodot;": '\U00002A00',
- "xopf;": '\U0001D569',
- "xoplus;": '\U00002A01',
- "xotime;": '\U00002A02',
- "xrArr;": '\U000027F9',
- "xrarr;": '\U000027F6',
- "xscr;": '\U0001D4CD',
- "xsqcup;": '\U00002A06',
- "xuplus;": '\U00002A04',
- "xutri;": '\U000025B3',
- "xvee;": '\U000022C1',
- "xwedge;": '\U000022C0',
- "yacute;": '\U000000FD',
- "yacy;": '\U0000044F',
- "ycirc;": '\U00000177',
- "ycy;": '\U0000044B',
- "yen;": '\U000000A5',
- "yfr;": '\U0001D536',
- "yicy;": '\U00000457',
- "yopf;": '\U0001D56A',
- "yscr;": '\U0001D4CE',
- "yucy;": '\U0000044E',
- "yuml;": '\U000000FF',
- "zacute;": '\U0000017A',
- "zcaron;": '\U0000017E',
- "zcy;": '\U00000437',
- "zdot;": '\U0000017C',
- "zeetrf;": '\U00002128',
- "zeta;": '\U000003B6',
- "zfr;": '\U0001D537',
- "zhcy;": '\U00000436',
- "zigrarr;": '\U000021DD',
- "zopf;": '\U0001D56B',
- "zscr;": '\U0001D4CF',
- "zwj;": '\U0000200D',
- "zwnj;": '\U0000200C',
- "AElig": '\U000000C6',
- "AMP": '\U00000026',
- "Aacute": '\U000000C1',
- "Acirc": '\U000000C2',
- "Agrave": '\U000000C0',
- "Aring": '\U000000C5',
- "Atilde": '\U000000C3',
- "Auml": '\U000000C4',
- "COPY": '\U000000A9',
- "Ccedil": '\U000000C7',
- "ETH": '\U000000D0',
- "Eacute": '\U000000C9',
- "Ecirc": '\U000000CA',
- "Egrave": '\U000000C8',
- "Euml": '\U000000CB',
- "GT": '\U0000003E',
- "Iacute": '\U000000CD',
- "Icirc": '\U000000CE',
- "Igrave": '\U000000CC',
- "Iuml": '\U000000CF',
- "LT": '\U0000003C',
- "Ntilde": '\U000000D1',
- "Oacute": '\U000000D3',
- "Ocirc": '\U000000D4',
- "Ograve": '\U000000D2',
- "Oslash": '\U000000D8',
- "Otilde": '\U000000D5',
- "Ouml": '\U000000D6',
- "QUOT": '\U00000022',
- "REG": '\U000000AE',
- "THORN": '\U000000DE',
- "Uacute": '\U000000DA',
- "Ucirc": '\U000000DB',
- "Ugrave": '\U000000D9',
- "Uuml": '\U000000DC',
- "Yacute": '\U000000DD',
- "aacute": '\U000000E1',
- "acirc": '\U000000E2',
- "acute": '\U000000B4',
- "aelig": '\U000000E6',
- "agrave": '\U000000E0',
- "amp": '\U00000026',
- "aring": '\U000000E5',
- "atilde": '\U000000E3',
- "auml": '\U000000E4',
- "brvbar": '\U000000A6',
- "ccedil": '\U000000E7',
- "cedil": '\U000000B8',
- "cent": '\U000000A2',
- "copy": '\U000000A9',
- "curren": '\U000000A4',
- "deg": '\U000000B0',
- "divide": '\U000000F7',
- "eacute": '\U000000E9',
- "ecirc": '\U000000EA',
- "egrave": '\U000000E8',
- "eth": '\U000000F0',
- "euml": '\U000000EB',
- "frac12": '\U000000BD',
- "frac14": '\U000000BC',
- "frac34": '\U000000BE',
- "gt": '\U0000003E',
- "iacute": '\U000000ED',
- "icirc": '\U000000EE',
- "iexcl": '\U000000A1',
- "igrave": '\U000000EC',
- "iquest": '\U000000BF',
- "iuml": '\U000000EF',
- "laquo": '\U000000AB',
- "lt": '\U0000003C',
- "macr": '\U000000AF',
- "micro": '\U000000B5',
- "middot": '\U000000B7',
- "nbsp": '\U000000A0',
- "not": '\U000000AC',
- "ntilde": '\U000000F1',
- "oacute": '\U000000F3',
- "ocirc": '\U000000F4',
- "ograve": '\U000000F2',
- "ordf": '\U000000AA',
- "ordm": '\U000000BA',
- "oslash": '\U000000F8',
- "otilde": '\U000000F5',
- "ouml": '\U000000F6',
- "para": '\U000000B6',
- "plusmn": '\U000000B1',
- "pound": '\U000000A3',
- "quot": '\U00000022',
- "raquo": '\U000000BB',
- "reg": '\U000000AE',
- "sect": '\U000000A7',
- "shy": '\U000000AD',
- "sup1": '\U000000B9',
- "sup2": '\U000000B2',
- "sup3": '\U000000B3',
- "szlig": '\U000000DF',
- "thorn": '\U000000FE',
- "times": '\U000000D7',
- "uacute": '\U000000FA',
- "ucirc": '\U000000FB',
- "ugrave": '\U000000F9',
- "uml": '\U000000A8',
- "uuml": '\U000000FC',
- "yacute": '\U000000FD',
- "yen": '\U000000A5',
- "yuml": '\U000000FF',
-}
-
-// HTML entities that are two unicode codepoints.
-var entity2 = map[string][2]rune{
- // TODO(nigeltao): Handle replacements that are wider than their names.
- // "nLt;": {'\u226A', '\u20D2'},
- // "nGt;": {'\u226B', '\u20D2'},
- "NotEqualTilde;": {'\u2242', '\u0338'},
- "NotGreaterFullEqual;": {'\u2267', '\u0338'},
- "NotGreaterGreater;": {'\u226B', '\u0338'},
- "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'},
- "NotHumpDownHump;": {'\u224E', '\u0338'},
- "NotHumpEqual;": {'\u224F', '\u0338'},
- "NotLeftTriangleBar;": {'\u29CF', '\u0338'},
- "NotLessLess;": {'\u226A', '\u0338'},
- "NotLessSlantEqual;": {'\u2A7D', '\u0338'},
- "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'},
- "NotNestedLessLess;": {'\u2AA1', '\u0338'},
- "NotPrecedesEqual;": {'\u2AAF', '\u0338'},
- "NotRightTriangleBar;": {'\u29D0', '\u0338'},
- "NotSquareSubset;": {'\u228F', '\u0338'},
- "NotSquareSuperset;": {'\u2290', '\u0338'},
- "NotSubset;": {'\u2282', '\u20D2'},
- "NotSucceedsEqual;": {'\u2AB0', '\u0338'},
- "NotSucceedsTilde;": {'\u227F', '\u0338'},
- "NotSuperset;": {'\u2283', '\u20D2'},
- "ThickSpace;": {'\u205F', '\u200A'},
- "acE;": {'\u223E', '\u0333'},
- "bne;": {'\u003D', '\u20E5'},
- "bnequiv;": {'\u2261', '\u20E5'},
- "caps;": {'\u2229', '\uFE00'},
- "cups;": {'\u222A', '\uFE00'},
- "fjlig;": {'\u0066', '\u006A'},
- "gesl;": {'\u22DB', '\uFE00'},
- "gvertneqq;": {'\u2269', '\uFE00'},
- "gvnE;": {'\u2269', '\uFE00'},
- "lates;": {'\u2AAD', '\uFE00'},
- "lesg;": {'\u22DA', '\uFE00'},
- "lvertneqq;": {'\u2268', '\uFE00'},
- "lvnE;": {'\u2268', '\uFE00'},
- "nGg;": {'\u22D9', '\u0338'},
- "nGtv;": {'\u226B', '\u0338'},
- "nLl;": {'\u22D8', '\u0338'},
- "nLtv;": {'\u226A', '\u0338'},
- "nang;": {'\u2220', '\u20D2'},
- "napE;": {'\u2A70', '\u0338'},
- "napid;": {'\u224B', '\u0338'},
- "nbump;": {'\u224E', '\u0338'},
- "nbumpe;": {'\u224F', '\u0338'},
- "ncongdot;": {'\u2A6D', '\u0338'},
- "nedot;": {'\u2250', '\u0338'},
- "nesim;": {'\u2242', '\u0338'},
- "ngE;": {'\u2267', '\u0338'},
- "ngeqq;": {'\u2267', '\u0338'},
- "ngeqslant;": {'\u2A7E', '\u0338'},
- "nges;": {'\u2A7E', '\u0338'},
- "nlE;": {'\u2266', '\u0338'},
- "nleqq;": {'\u2266', '\u0338'},
- "nleqslant;": {'\u2A7D', '\u0338'},
- "nles;": {'\u2A7D', '\u0338'},
- "notinE;": {'\u22F9', '\u0338'},
- "notindot;": {'\u22F5', '\u0338'},
- "nparsl;": {'\u2AFD', '\u20E5'},
- "npart;": {'\u2202', '\u0338'},
- "npre;": {'\u2AAF', '\u0338'},
- "npreceq;": {'\u2AAF', '\u0338'},
- "nrarrc;": {'\u2933', '\u0338'},
- "nrarrw;": {'\u219D', '\u0338'},
- "nsce;": {'\u2AB0', '\u0338'},
- "nsubE;": {'\u2AC5', '\u0338'},
- "nsubset;": {'\u2282', '\u20D2'},
- "nsubseteqq;": {'\u2AC5', '\u0338'},
- "nsucceq;": {'\u2AB0', '\u0338'},
- "nsupE;": {'\u2AC6', '\u0338'},
- "nsupset;": {'\u2283', '\u20D2'},
- "nsupseteqq;": {'\u2AC6', '\u0338'},
- "nvap;": {'\u224D', '\u20D2'},
- "nvge;": {'\u2265', '\u20D2'},
- "nvgt;": {'\u003E', '\u20D2'},
- "nvle;": {'\u2264', '\u20D2'},
- "nvlt;": {'\u003C', '\u20D2'},
- "nvltrie;": {'\u22B4', '\u20D2'},
- "nvrtrie;": {'\u22B5', '\u20D2'},
- "nvsim;": {'\u223C', '\u20D2'},
- "race;": {'\u223D', '\u0331'},
- "smtes;": {'\u2AAC', '\uFE00'},
- "sqcaps;": {'\u2293', '\uFE00'},
- "sqcups;": {'\u2294', '\uFE00'},
- "varsubsetneq;": {'\u228A', '\uFE00'},
- "varsubsetneqq;": {'\u2ACB', '\uFE00'},
- "varsupsetneq;": {'\u228B', '\uFE00'},
- "varsupsetneqq;": {'\u2ACC', '\uFE00'},
- "vnsub;": {'\u2282', '\u20D2'},
- "vnsup;": {'\u2283', '\u20D2'},
- "vsubnE;": {'\u2ACB', '\uFE00'},
- "vsubne;": {'\u228A', '\uFE00'},
- "vsupnE;": {'\u2ACC', '\uFE00'},
- "vsupne;": {'\u228B', '\uFE00'},
-}
diff --git a/vendor/golang.org/x/net/html/escape.go b/vendor/golang.org/x/net/html/escape.go
deleted file mode 100644
index 04c6bec210..0000000000
--- a/vendor/golang.org/x/net/html/escape.go
+++ /dev/null
@@ -1,339 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package html
-
-import (
- "bytes"
- "strings"
- "unicode/utf8"
-)
-
-// These replacements permit compatibility with old numeric entities that
-// assumed Windows-1252 encoding.
-// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
-var replacementTable = [...]rune{
- '\u20AC', // First entry is what 0x80 should be replaced with.
- '\u0081',
- '\u201A',
- '\u0192',
- '\u201E',
- '\u2026',
- '\u2020',
- '\u2021',
- '\u02C6',
- '\u2030',
- '\u0160',
- '\u2039',
- '\u0152',
- '\u008D',
- '\u017D',
- '\u008F',
- '\u0090',
- '\u2018',
- '\u2019',
- '\u201C',
- '\u201D',
- '\u2022',
- '\u2013',
- '\u2014',
- '\u02DC',
- '\u2122',
- '\u0161',
- '\u203A',
- '\u0153',
- '\u009D',
- '\u017E',
- '\u0178', // Last entry is 0x9F.
- // 0x00->'\uFFFD' is handled programmatically.
- // 0x0D->'\u000D' is a no-op.
-}
-
-// unescapeEntity reads an entity like "<" from b[src:] and writes the
-// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
-// Precondition: b[src] == '&' && dst <= src.
-// attribute should be true if parsing an attribute value.
-func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
- // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
-
- // i starts at 1 because we already know that s[0] == '&'.
- i, s := 1, b[src:]
-
- if len(s) <= 1 {
- b[dst] = b[src]
- return dst + 1, src + 1
- }
-
- if s[i] == '#' {
- if len(s) <= 3 { // We need to have at least ".".
- b[dst] = b[src]
- return dst + 1, src + 1
- }
- i++
- c := s[i]
- hex := false
- if c == 'x' || c == 'X' {
- hex = true
- i++
- }
-
- x := '\x00'
- for i < len(s) {
- c = s[i]
- i++
- if hex {
- if '0' <= c && c <= '9' {
- x = 16*x + rune(c) - '0'
- continue
- } else if 'a' <= c && c <= 'f' {
- x = 16*x + rune(c) - 'a' + 10
- continue
- } else if 'A' <= c && c <= 'F' {
- x = 16*x + rune(c) - 'A' + 10
- continue
- }
- } else if '0' <= c && c <= '9' {
- x = 10*x + rune(c) - '0'
- continue
- }
- if c != ';' {
- i--
- }
- break
- }
-
- if i <= 3 { // No characters matched.
- b[dst] = b[src]
- return dst + 1, src + 1
- }
-
- if 0x80 <= x && x <= 0x9F {
- // Replace characters from Windows-1252 with UTF-8 equivalents.
- x = replacementTable[x-0x80]
- } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
- // Replace invalid characters with the replacement character.
- x = '\uFFFD'
- }
-
- return dst + utf8.EncodeRune(b[dst:], x), src + i
- }
-
- // Consume the maximum number of characters possible, with the
- // consumed characters matching one of the named references.
-
- for i < len(s) {
- c := s[i]
- i++
- // Lower-cased characters are more common in entities, so we check for them first.
- if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' {
- continue
- }
- if c != ';' {
- i--
- }
- break
- }
-
- entityName := string(s[1:i])
- if entityName == "" {
- // No-op.
- } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' {
- // No-op.
- } else if x := entity[entityName]; x != 0 {
- return dst + utf8.EncodeRune(b[dst:], x), src + i
- } else if x := entity2[entityName]; x[0] != 0 {
- dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
- return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
- } else if !attribute {
- maxLen := len(entityName) - 1
- if maxLen > longestEntityWithoutSemicolon {
- maxLen = longestEntityWithoutSemicolon
- }
- for j := maxLen; j > 1; j-- {
- if x := entity[entityName[:j]]; x != 0 {
- return dst + utf8.EncodeRune(b[dst:], x), src + j + 1
- }
- }
- }
-
- dst1, src1 = dst+i, src+i
- copy(b[dst:dst1], b[src:src1])
- return dst1, src1
-}
-
-// unescape unescapes b's entities in-place, so that "a<b" becomes "a' byte that, per above, we'd like to avoid escaping unless we have to.
-//
-// Studying the summary table (and T actions in its '>' column) closely, we
-// only need to escape in states 43, 44, 49, 51 and 52. State 43 is at the
-// start of the comment data. State 52 is after a '!'. The other three states
-// are after a '-'.
-//
-// Our algorithm is thus to escape every '&' and to escape '>' if and only if:
-// - The '>' is after a '!' or '-' (in the unescaped data) or
-// - The '>' is at the start of the comment data (after the opening ""); err != nil {
- return err
- }
- return nil
- case DoctypeNode:
- if _, err := w.WriteString("')
- case RawNode:
- _, err := w.WriteString(n.Data)
- return err
- default:
- return errors.New("html: unknown node type")
- }
-
- // Render the
.
- SelfClosingTagToken
- // A CommentToken looks like .
- CommentToken
- // A DoctypeToken looks like
- DoctypeToken
-)
-
-// ErrBufferExceeded means that the buffering limit was exceeded.
-var ErrBufferExceeded = errors.New("max buffer exceeded")
-
-// String returns a string representation of the TokenType.
-func (t TokenType) String() string {
- switch t {
- case ErrorToken:
- return "Error"
- case TextToken:
- return "Text"
- case StartTagToken:
- return "StartTag"
- case EndTagToken:
- return "EndTag"
- case SelfClosingTagToken:
- return "SelfClosingTag"
- case CommentToken:
- return "Comment"
- case DoctypeToken:
- return "Doctype"
- }
- return "Invalid(" + strconv.Itoa(int(t)) + ")"
-}
-
-// An Attribute is an attribute namespace-key-value triple. Namespace is
-// non-empty for foreign attributes like xlink, Key is alphabetic (and hence
-// does not contain escapable characters like '&', '<' or '>'), and Val is
-// unescaped (it looks like "a"
- case EndTagToken:
- return "" + t.tagString() + ">"
- case SelfClosingTagToken:
- return "<" + t.tagString() + "/>"
- case CommentToken:
- return ""
- case DoctypeToken:
- return ""
- }
- return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
-}
-
-// span is a range of bytes in a Tokenizer's buffer. The start is inclusive,
-// the end is exclusive.
-type span struct {
- start, end int
-}
-
-// A Tokenizer returns a stream of HTML Tokens.
-type Tokenizer struct {
- // r is the source of the HTML text.
- r io.Reader
- // tt is the TokenType of the current token.
- tt TokenType
- // err is the first error encountered during tokenization. It is possible
- // for tt != Error && err != nil to hold: this means that Next returned a
- // valid token but the subsequent Next call will return an error token.
- // For example, if the HTML text input was just "plain", then the first
- // Next call would set z.err to io.EOF but return a TextToken, and all
- // subsequent Next calls would return an ErrorToken.
- // err is never reset. Once it becomes non-nil, it stays non-nil.
- err error
- // readErr is the error returned by the io.Reader r. It is separate from
- // err because it is valid for an io.Reader to return (n int, err1 error)
- // such that n > 0 && err1 != nil, and callers should always process the
- // n > 0 bytes before considering the error err1.
- readErr error
- // buf[raw.start:raw.end] holds the raw bytes of the current token.
- // buf[raw.end:] is buffered input that will yield future tokens.
- raw span
- buf []byte
- // maxBuf limits the data buffered in buf. A value of 0 means unlimited.
- maxBuf int
- // buf[data.start:data.end] holds the raw bytes of the current token's data:
- // a text token's text, a tag token's tag name, etc.
- data span
- // pendingAttr is the attribute key and value currently being tokenized.
- // When complete, pendingAttr is pushed onto attr. nAttrReturned is
- // incremented on each call to TagAttr.
- pendingAttr [2]span
- attr [][2]span
- nAttrReturned int
- // rawTag is the "script" in "" that closes the next token. If
- // non-empty, the subsequent call to Next will return a raw or RCDATA text
- // token: one that treats "
" as text instead of an element. - // rawTag's contents are lower-cased. - rawTag string - // textIsRaw is whether the current text token's data is not escaped. - textIsRaw bool - // convertNUL is whether NUL bytes in the current token's data should - // be converted into \ufffd replacement characters. - convertNUL bool - // allowCDATA is whether CDATA sections are allowed in the current context. - allowCDATA bool -} - -// AllowCDATA sets whether or not the tokenizer recognizes as -// the text "foo". The default value is false, which means to recognize it as -// a bogus comment "" instead. -// -// Strictly speaking, an HTML5 compliant tokenizer should allow CDATA if and -// only if tokenizing foreign content, such as MathML and SVG. However, -// tracking foreign-contentness is difficult to do purely in the tokenizer, -// as opposed to the parser, due to HTML integration points: an