Initial connection
Signed-off-by: Vincent Batts <vbatts@hashbangbash.com>
This commit is contained in:
parent
e595e90e38
commit
61b81742d3
194 changed files with 89534 additions and 0 deletions
199
Godeps/Godeps.json
generated
Normal file
199
Godeps/Godeps.json
generated
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
{
|
||||||
|
"ImportPath": "git.thisco.de/vbatts/cri",
|
||||||
|
"GoVersion": "go1.9",
|
||||||
|
"GodepVersion": "v79",
|
||||||
|
"Packages": [
|
||||||
|
"google.golang.org/grpc/grpclb/grpc_lb_v1/messages",
|
||||||
|
"google.golang.org/grpc",
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime",
|
||||||
|
"google.golang.org/grpc/grpclb/grpc_lb_v1/service"
|
||||||
|
],
|
||||||
|
"Deps": [
|
||||||
|
{
|
||||||
|
"ImportPath": "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime",
|
||||||
|
"Rev": "507af4b9c222907a212234f62484e83fdeefe394"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/golang/glog",
|
||||||
|
"Rev": "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/golang/protobuf/proto",
|
||||||
|
"Rev": "130e6b02ab059e7b717a096f397c5b60111cae74"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/golang/protobuf/ptypes",
|
||||||
|
"Rev": "130e6b02ab059e7b717a096f397c5b60111cae74"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/golang/protobuf/ptypes/any",
|
||||||
|
"Rev": "130e6b02ab059e7b717a096f397c5b60111cae74"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/golang/protobuf/ptypes/duration",
|
||||||
|
"Rev": "130e6b02ab059e7b717a096f397c5b60111cae74"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/golang/protobuf/ptypes/timestamp",
|
||||||
|
"Rev": "130e6b02ab059e7b717a096f397c5b60111cae74"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/context",
|
||||||
|
"Rev": "a04bdaca5b32abe1c069418fb7088ae607de5bd0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/http2",
|
||||||
|
"Rev": "a04bdaca5b32abe1c069418fb7088ae607de5bd0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/http2/hpack",
|
||||||
|
"Rev": "a04bdaca5b32abe1c069418fb7088ae607de5bd0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/idna",
|
||||||
|
"Rev": "a04bdaca5b32abe1c069418fb7088ae607de5bd0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/internal/timeseries",
|
||||||
|
"Rev": "a04bdaca5b32abe1c069418fb7088ae607de5bd0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/lex/httplex",
|
||||||
|
"Rev": "a04bdaca5b32abe1c069418fb7088ae607de5bd0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/trace",
|
||||||
|
"Rev": "a04bdaca5b32abe1c069418fb7088ae607de5bd0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/text/secure/bidirule",
|
||||||
|
"Rev": "1cbadb444a806fd9430d14ad08967ed91da4fa0a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/text/transform",
|
||||||
|
"Rev": "1cbadb444a806fd9430d14ad08967ed91da4fa0a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/text/unicode/bidi",
|
||||||
|
"Rev": "1cbadb444a806fd9430d14ad08967ed91da4fa0a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/text/unicode/norm",
|
||||||
|
"Rev": "1cbadb444a806fd9430d14ad08967ed91da4fa0a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/genproto/googleapis/rpc/status",
|
||||||
|
"Rev": "f676e0f3ac6395ff1a529ae59a6670878a8371a6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/balancer",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/codes",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/connectivity",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/credentials",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/grpclb/grpc_lb_v1/messages",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/grpclb/grpc_lb_v1/service",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/grpclog",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/grpclog/glogger",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/internal",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/keepalive",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/metadata",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/naming",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/peer",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/resolver",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/resolver/manual",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/stats",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/status",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/tap",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/test/codec_perf",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/test/leakcheck",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/transport",
|
||||||
|
"Comment": "v1.2.0-277-g3bf110c",
|
||||||
|
"Rev": "3bf110cd0cef4e896aa6331d44ca4a0c407bbaf3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
5
Godeps/Readme
generated
Normal file
5
Godeps/Readme
generated
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
This directory tree is generated automatically by godep.
|
||||||
|
|
||||||
|
Please do not edit.
|
||||||
|
|
||||||
|
See https://github.com/tools/godep for more information.
|
32
grpc.go
Normal file
32
grpc.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package cri
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetClientConn is a convenience for connecting to a gprc unix socket.
|
||||||
|
func GetClientConn(connStr string, timeout time.Duration) (*grpc.ClientConn, error) {
|
||||||
|
conn, err := grpc.Dial(connStr, grpc.WithInsecure(), grpc.WithTimeout(timeout),
|
||||||
|
grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
|
||||||
|
return net.DialTimeout("unix", addr, timeout)
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to connect: %v", err)
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRuntimeServiceClient is a passthrough to kubernetes CRI v1alpha1/runtime
|
||||||
|
func NewRuntimeServiceClient(conn *grpc.ClientConn) pb.RuntimeServiceClient {
|
||||||
|
return pb.NewRuntimeServiceClient(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewImageServiceClient is a passthrough to kubernetes CRI v1alpha1/runtime
|
||||||
|
func NewImageServiceClient(conn *grpc.ClientConn) pb.ImageServiceClient {
|
||||||
|
return pb.NewImageServiceClient(conn)
|
||||||
|
}
|
15
vendor/github.com/gogo/protobuf/AUTHORS
generated
vendored
Normal file
15
vendor/github.com/gogo/protobuf/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# This is the official list of GoGo authors for copyright purposes.
|
||||||
|
# This file is distinct from the CONTRIBUTORS file, which
|
||||||
|
# lists people. For example, employees are listed in CONTRIBUTORS,
|
||||||
|
# but not in AUTHORS, because the employer holds the copyright.
|
||||||
|
|
||||||
|
# Names should be added to this file as one of
|
||||||
|
# Organization's name
|
||||||
|
# Individual's name <submission email address>
|
||||||
|
# Individual's name <submission email address> <email2> <emailN>
|
||||||
|
|
||||||
|
# Please keep the list sorted.
|
||||||
|
|
||||||
|
Sendgrid, Inc
|
||||||
|
Vastech SA (PTY) LTD
|
||||||
|
Walter Schulze <awalterschulze@gmail.com>
|
22
vendor/github.com/gogo/protobuf/CONTRIBUTORS
generated
vendored
Normal file
22
vendor/github.com/gogo/protobuf/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Anton Povarov <anton.povarov@gmail.com>
|
||||||
|
Brian Goff <cpuguy83@gmail.com>
|
||||||
|
Clayton Coleman <ccoleman@redhat.com>
|
||||||
|
Denis Smirnov <denis.smirnov.91@gmail.com>
|
||||||
|
DongYun Kang <ceram1000@gmail.com>
|
||||||
|
Dwayne Schultz <dschultz@pivotal.io>
|
||||||
|
Georg Apitz <gapitz@pivotal.io>
|
||||||
|
Gustav Paul <gustav.paul@gmail.com>
|
||||||
|
Johan Brandhorst <johan.brandhorst@gmail.com>
|
||||||
|
John Shahid <jvshahid@gmail.com>
|
||||||
|
John Tuley <john@tuley.org>
|
||||||
|
Laurent <laurent@adyoulike.com>
|
||||||
|
Patrick Lee <patrick@dropbox.com>
|
||||||
|
Roger Johansson <rogeralsing@gmail.com>
|
||||||
|
Sam Nguyen <sam.nguyen@sendgrid.com>
|
||||||
|
Sergio Arbeo <serabe@gmail.com>
|
||||||
|
Stephen J Day <stephen.day@docker.com>
|
||||||
|
Tamir Duberstein <tamird@gmail.com>
|
||||||
|
Todd Eisenberger <teisenberger@dropbox.com>
|
||||||
|
Tormod Erevik Lea <tormodlea@gmail.com>
|
||||||
|
Vyacheslav Kim <kane@sendgrid.com>
|
||||||
|
Walter Schulze <awalterschulze@gmail.com>
|
36
vendor/github.com/gogo/protobuf/LICENSE
generated
vendored
Normal file
36
vendor/github.com/gogo/protobuf/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
Protocol Buffers for Go with Gadgets
|
||||||
|
|
||||||
|
Copyright (c) 2013, The GoGo Authors. All rights reserved.
|
||||||
|
http://github.com/gogo/protobuf
|
||||||
|
|
||||||
|
Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
|
||||||
|
Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
https://github.com/golang/protobuf
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. 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.
|
||||||
|
|
191
vendor/github.com/golang/glog/LICENSE
generated
vendored
Normal file
191
vendor/github.com/golang/glog/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
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:
|
||||||
|
|
||||||
|
You must give any other recipients of the Work or Derivative Works a copy of
|
||||||
|
this License; and
|
||||||
|
You must cause any modified files to carry prominent notices stating that You
|
||||||
|
changed the files; and
|
||||||
|
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
|
||||||
|
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.
|
44
vendor/github.com/golang/glog/README
generated
vendored
Normal file
44
vendor/github.com/golang/glog/README
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
glog
|
||||||
|
====
|
||||||
|
|
||||||
|
Leveled execution logs for Go.
|
||||||
|
|
||||||
|
This is an efficient pure Go implementation of leveled logs in the
|
||||||
|
manner of the open source C++ package
|
||||||
|
https://github.com/google/glog
|
||||||
|
|
||||||
|
By binding methods to booleans it is possible to use the log package
|
||||||
|
without paying the expense of evaluating the arguments to the log.
|
||||||
|
Through the -vmodule flag, the package also provides fine-grained
|
||||||
|
control over logging at the file level.
|
||||||
|
|
||||||
|
The comment from glog.go introduces the ideas:
|
||||||
|
|
||||||
|
Package glog implements logging analogous to the Google-internal
|
||||||
|
C++ INFO/ERROR/V setup. It provides functions Info, Warning,
|
||||||
|
Error, Fatal, plus formatting variants such as Infof. It
|
||||||
|
also provides V-style logging controlled by the -v and
|
||||||
|
-vmodule=file=2 flags.
|
||||||
|
|
||||||
|
Basic examples:
|
||||||
|
|
||||||
|
glog.Info("Prepare to repel boarders")
|
||||||
|
|
||||||
|
glog.Fatalf("Initialization failed: %s", err)
|
||||||
|
|
||||||
|
See the documentation for the V function for an explanation
|
||||||
|
of these examples:
|
||||||
|
|
||||||
|
if glog.V(2) {
|
||||||
|
glog.Info("Starting transaction...")
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(2).Infoln("Processed", nItems, "elements")
|
||||||
|
|
||||||
|
|
||||||
|
The repository contains an open source version of the log package
|
||||||
|
used inside Google. The master copy of the source lives inside
|
||||||
|
Google, not here. The code in this repo is for export only and is not itself
|
||||||
|
under development. Feature requests will be ignored.
|
||||||
|
|
||||||
|
Send bug reports to golang-nuts@googlegroups.com.
|
1180
vendor/github.com/golang/glog/glog.go
generated
vendored
Normal file
1180
vendor/github.com/golang/glog/glog.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
124
vendor/github.com/golang/glog/glog_file.go
generated
vendored
Normal file
124
vendor/github.com/golang/glog/glog_file.go
generated
vendored
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
// Go support for leveled logs, analogous to https://code.google.com/p/google-glog/
|
||||||
|
//
|
||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// File I/O for logs.
|
||||||
|
|
||||||
|
package glog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaxSize is the maximum size of a log file in bytes.
|
||||||
|
var MaxSize uint64 = 1024 * 1024 * 1800
|
||||||
|
|
||||||
|
// logDirs lists the candidate directories for new log files.
|
||||||
|
var logDirs []string
|
||||||
|
|
||||||
|
// If non-empty, overrides the choice of directory in which to write logs.
|
||||||
|
// See createLogDirs for the full list of possible destinations.
|
||||||
|
var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory")
|
||||||
|
|
||||||
|
func createLogDirs() {
|
||||||
|
if *logDir != "" {
|
||||||
|
logDirs = append(logDirs, *logDir)
|
||||||
|
}
|
||||||
|
logDirs = append(logDirs, os.TempDir())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
pid = os.Getpid()
|
||||||
|
program = filepath.Base(os.Args[0])
|
||||||
|
host = "unknownhost"
|
||||||
|
userName = "unknownuser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
h, err := os.Hostname()
|
||||||
|
if err == nil {
|
||||||
|
host = shortHostname(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
current, err := user.Current()
|
||||||
|
if err == nil {
|
||||||
|
userName = current.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize userName since it may contain filepath separators on Windows.
|
||||||
|
userName = strings.Replace(userName, `\`, "_", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// shortHostname returns its argument, truncating at the first period.
|
||||||
|
// For instance, given "www.google.com" it returns "www".
|
||||||
|
func shortHostname(hostname string) string {
|
||||||
|
if i := strings.Index(hostname, "."); i >= 0 {
|
||||||
|
return hostname[:i]
|
||||||
|
}
|
||||||
|
return hostname
|
||||||
|
}
|
||||||
|
|
||||||
|
// logName returns a new log file name containing tag, with start time t, and
|
||||||
|
// the name for the symlink for tag.
|
||||||
|
func logName(tag string, t time.Time) (name, link string) {
|
||||||
|
name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d",
|
||||||
|
program,
|
||||||
|
host,
|
||||||
|
userName,
|
||||||
|
tag,
|
||||||
|
t.Year(),
|
||||||
|
t.Month(),
|
||||||
|
t.Day(),
|
||||||
|
t.Hour(),
|
||||||
|
t.Minute(),
|
||||||
|
t.Second(),
|
||||||
|
pid)
|
||||||
|
return name, program + "." + tag
|
||||||
|
}
|
||||||
|
|
||||||
|
var onceLogDirs sync.Once
|
||||||
|
|
||||||
|
// create creates a new log file and returns the file and its filename, which
|
||||||
|
// contains tag ("INFO", "FATAL", etc.) and t. If the file is created
|
||||||
|
// successfully, create also attempts to update the symlink for that tag, ignoring
|
||||||
|
// errors.
|
||||||
|
func create(tag string, t time.Time) (f *os.File, filename string, err error) {
|
||||||
|
onceLogDirs.Do(createLogDirs)
|
||||||
|
if len(logDirs) == 0 {
|
||||||
|
return nil, "", errors.New("log: no log dirs")
|
||||||
|
}
|
||||||
|
name, link := logName(tag, t)
|
||||||
|
var lastErr error
|
||||||
|
for _, dir := range logDirs {
|
||||||
|
fname := filepath.Join(dir, name)
|
||||||
|
f, err := os.Create(fname)
|
||||||
|
if err == nil {
|
||||||
|
symlink := filepath.Join(dir, link)
|
||||||
|
os.Remove(symlink) // ignore err
|
||||||
|
os.Symlink(name, symlink) // ignore err
|
||||||
|
return f, fname, nil
|
||||||
|
}
|
||||||
|
lastErr = err
|
||||||
|
}
|
||||||
|
return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr)
|
||||||
|
}
|
3
vendor/github.com/golang/protobuf/AUTHORS
generated
vendored
Normal file
3
vendor/github.com/golang/protobuf/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/AUTHORS.
|
3
vendor/github.com/golang/protobuf/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/github.com/golang/protobuf/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/CONTRIBUTORS.
|
31
vendor/github.com/golang/protobuf/LICENSE
generated
vendored
Normal file
31
vendor/github.com/golang/protobuf/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
|
||||||
|
Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
https://github.com/golang/protobuf
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. 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.
|
||||||
|
|
43
vendor/github.com/golang/protobuf/proto/Makefile
generated
vendored
Normal file
43
vendor/github.com/golang/protobuf/proto/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
# Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
#
|
||||||
|
# Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
# https://github.com/golang/protobuf
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above
|
||||||
|
# copyright notice, this list of conditions and the following disclaimer
|
||||||
|
# in the documentation and/or other materials provided with the
|
||||||
|
# distribution.
|
||||||
|
# * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
install:
|
||||||
|
go install
|
||||||
|
|
||||||
|
test: install generate-test-pbs
|
||||||
|
go test
|
||||||
|
|
||||||
|
|
||||||
|
generate-test-pbs:
|
||||||
|
make install
|
||||||
|
make -C testdata
|
||||||
|
protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto
|
||||||
|
make
|
229
vendor/github.com/golang/protobuf/proto/clone.go
generated
vendored
Normal file
229
vendor/github.com/golang/protobuf/proto/clone.go
generated
vendored
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
// Protocol buffer deep copy and merge.
|
||||||
|
// TODO: RawMessage.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Clone returns a deep copy of a protocol buffer.
|
||||||
|
func Clone(pb Message) Message {
|
||||||
|
in := reflect.ValueOf(pb)
|
||||||
|
if in.IsNil() {
|
||||||
|
return pb
|
||||||
|
}
|
||||||
|
|
||||||
|
out := reflect.New(in.Type().Elem())
|
||||||
|
// out is empty so a merge is a deep copy.
|
||||||
|
mergeStruct(out.Elem(), in.Elem())
|
||||||
|
return out.Interface().(Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge merges src into dst.
|
||||||
|
// Required and optional fields that are set in src will be set to that value in dst.
|
||||||
|
// Elements of repeated fields will be appended.
|
||||||
|
// Merge panics if src and dst are not the same type, or if dst is nil.
|
||||||
|
func Merge(dst, src Message) {
|
||||||
|
in := reflect.ValueOf(src)
|
||||||
|
out := reflect.ValueOf(dst)
|
||||||
|
if out.IsNil() {
|
||||||
|
panic("proto: nil destination")
|
||||||
|
}
|
||||||
|
if in.Type() != out.Type() {
|
||||||
|
// Explicit test prior to mergeStruct so that mistyped nils will fail
|
||||||
|
panic("proto: type mismatch")
|
||||||
|
}
|
||||||
|
if in.IsNil() {
|
||||||
|
// Merging nil into non-nil is a quiet no-op
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mergeStruct(out.Elem(), in.Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeStruct(out, in reflect.Value) {
|
||||||
|
sprop := GetProperties(in.Type())
|
||||||
|
for i := 0; i < in.NumField(); i++ {
|
||||||
|
f := in.Type().Field(i)
|
||||||
|
if strings.HasPrefix(f.Name, "XXX_") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
if emIn, ok := extendable(in.Addr().Interface()); ok {
|
||||||
|
emOut, _ := extendable(out.Addr().Interface())
|
||||||
|
mIn, muIn := emIn.extensionsRead()
|
||||||
|
if mIn != nil {
|
||||||
|
mOut := emOut.extensionsWrite()
|
||||||
|
muIn.Lock()
|
||||||
|
mergeExtension(mOut, mIn)
|
||||||
|
muIn.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uf := in.FieldByName("XXX_unrecognized")
|
||||||
|
if !uf.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uin := uf.Bytes()
|
||||||
|
if len(uin) > 0 {
|
||||||
|
out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeAny performs a merge between two values of the same type.
|
||||||
|
// viaPtr indicates whether the values were indirected through a pointer (implying proto2).
|
||||||
|
// prop is set if this is a struct field (it may be nil).
|
||||||
|
func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) {
|
||||||
|
if in.Type() == protoMessageType {
|
||||||
|
if !in.IsNil() {
|
||||||
|
if out.IsNil() {
|
||||||
|
out.Set(reflect.ValueOf(Clone(in.Interface().(Message))))
|
||||||
|
} else {
|
||||||
|
Merge(out.Interface().(Message), in.Interface().(Message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch in.Kind() {
|
||||||
|
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.String, reflect.Uint32, reflect.Uint64:
|
||||||
|
if !viaPtr && isProto3Zero(in) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out.Set(in)
|
||||||
|
case reflect.Interface:
|
||||||
|
// Probably a oneof field; copy non-nil values.
|
||||||
|
if in.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Allocate destination if it is not set, or set to a different type.
|
||||||
|
// Otherwise we will merge as normal.
|
||||||
|
if out.IsNil() || out.Elem().Type() != in.Elem().Type() {
|
||||||
|
out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T)
|
||||||
|
}
|
||||||
|
mergeAny(out.Elem(), in.Elem(), false, nil)
|
||||||
|
case reflect.Map:
|
||||||
|
if in.Len() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if out.IsNil() {
|
||||||
|
out.Set(reflect.MakeMap(in.Type()))
|
||||||
|
}
|
||||||
|
// For maps with value types of *T or []byte we need to deep copy each value.
|
||||||
|
elemKind := in.Type().Elem().Kind()
|
||||||
|
for _, key := range in.MapKeys() {
|
||||||
|
var val reflect.Value
|
||||||
|
switch elemKind {
|
||||||
|
case reflect.Ptr:
|
||||||
|
val = reflect.New(in.Type().Elem().Elem())
|
||||||
|
mergeAny(val, in.MapIndex(key), false, nil)
|
||||||
|
case reflect.Slice:
|
||||||
|
val = in.MapIndex(key)
|
||||||
|
val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
|
||||||
|
default:
|
||||||
|
val = in.MapIndex(key)
|
||||||
|
}
|
||||||
|
out.SetMapIndex(key, val)
|
||||||
|
}
|
||||||
|
case reflect.Ptr:
|
||||||
|
if in.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if out.IsNil() {
|
||||||
|
out.Set(reflect.New(in.Elem().Type()))
|
||||||
|
}
|
||||||
|
mergeAny(out.Elem(), in.Elem(), true, nil)
|
||||||
|
case reflect.Slice:
|
||||||
|
if in.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if in.Type().Elem().Kind() == reflect.Uint8 {
|
||||||
|
// []byte is a scalar bytes field, not a repeated field.
|
||||||
|
|
||||||
|
// Edge case: if this is in a proto3 message, a zero length
|
||||||
|
// bytes field is considered the zero value, and should not
|
||||||
|
// be merged.
|
||||||
|
if prop != nil && prop.proto3 && in.Len() == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a deep copy.
|
||||||
|
// Append to []byte{} instead of []byte(nil) so that we never end up
|
||||||
|
// with a nil result.
|
||||||
|
out.SetBytes(append([]byte{}, in.Bytes()...))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n := in.Len()
|
||||||
|
if out.IsNil() {
|
||||||
|
out.Set(reflect.MakeSlice(in.Type(), 0, n))
|
||||||
|
}
|
||||||
|
switch in.Type().Elem().Kind() {
|
||||||
|
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
|
||||||
|
reflect.String, reflect.Uint32, reflect.Uint64:
|
||||||
|
out.Set(reflect.AppendSlice(out, in))
|
||||||
|
default:
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
x := reflect.Indirect(reflect.New(in.Type().Elem()))
|
||||||
|
mergeAny(x, in.Index(i), false, nil)
|
||||||
|
out.Set(reflect.Append(out, x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
mergeStruct(out, in)
|
||||||
|
default:
|
||||||
|
// unknown type, so not a protocol buffer
|
||||||
|
log.Printf("proto: don't know how to copy %v", in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeExtension(out, in map[int32]Extension) {
|
||||||
|
for extNum, eIn := range in {
|
||||||
|
eOut := Extension{desc: eIn.desc}
|
||||||
|
if eIn.value != nil {
|
||||||
|
v := reflect.New(reflect.TypeOf(eIn.value)).Elem()
|
||||||
|
mergeAny(v, reflect.ValueOf(eIn.value), false, nil)
|
||||||
|
eOut.value = v.Interface()
|
||||||
|
}
|
||||||
|
if eIn.enc != nil {
|
||||||
|
eOut.enc = make([]byte, len(eIn.enc))
|
||||||
|
copy(eOut.enc, eIn.enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
out[extNum] = eOut
|
||||||
|
}
|
||||||
|
}
|
970
vendor/github.com/golang/protobuf/proto/decode.go
generated
vendored
Normal file
970
vendor/github.com/golang/protobuf/proto/decode.go
generated
vendored
Normal file
|
@ -0,0 +1,970 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routines for decoding protocol buffer data to construct in-memory representations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errOverflow is returned when an integer is too large to be represented.
|
||||||
|
var errOverflow = errors.New("proto: integer overflow")
|
||||||
|
|
||||||
|
// ErrInternalBadWireType is returned by generated code when an incorrect
|
||||||
|
// wire type is encountered. It does not get returned to user code.
|
||||||
|
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
|
||||||
|
|
||||||
|
// The fundamental decoders that interpret bytes on the wire.
|
||||||
|
// Those that take integer types all return uint64 and are
|
||||||
|
// therefore of type valueDecoder.
|
||||||
|
|
||||||
|
// DecodeVarint reads a varint-encoded integer from the slice.
|
||||||
|
// It returns the integer and the number of bytes consumed, or
|
||||||
|
// zero if there is not enough.
|
||||||
|
// This is the format for the
|
||||||
|
// int32, int64, uint32, uint64, bool, and enum
|
||||||
|
// protocol buffer types.
|
||||||
|
func DecodeVarint(buf []byte) (x uint64, n int) {
|
||||||
|
for shift := uint(0); shift < 64; shift += 7 {
|
||||||
|
if n >= len(buf) {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
b := uint64(buf[n])
|
||||||
|
n++
|
||||||
|
x |= (b & 0x7F) << shift
|
||||||
|
if (b & 0x80) == 0 {
|
||||||
|
return x, n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The number is too large to represent in a 64-bit value.
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Buffer) decodeVarintSlow() (x uint64, err error) {
|
||||||
|
i := p.index
|
||||||
|
l := len(p.buf)
|
||||||
|
|
||||||
|
for shift := uint(0); shift < 64; shift += 7 {
|
||||||
|
if i >= l {
|
||||||
|
err = io.ErrUnexpectedEOF
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b := p.buf[i]
|
||||||
|
i++
|
||||||
|
x |= (uint64(b) & 0x7F) << shift
|
||||||
|
if b < 0x80 {
|
||||||
|
p.index = i
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The number is too large to represent in a 64-bit value.
|
||||||
|
err = errOverflow
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeVarint reads a varint-encoded integer from the Buffer.
|
||||||
|
// This is the format for the
|
||||||
|
// int32, int64, uint32, uint64, bool, and enum
|
||||||
|
// protocol buffer types.
|
||||||
|
func (p *Buffer) DecodeVarint() (x uint64, err error) {
|
||||||
|
i := p.index
|
||||||
|
buf := p.buf
|
||||||
|
|
||||||
|
if i >= len(buf) {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
} else if buf[i] < 0x80 {
|
||||||
|
p.index++
|
||||||
|
return uint64(buf[i]), nil
|
||||||
|
} else if len(buf)-i < 10 {
|
||||||
|
return p.decodeVarintSlow()
|
||||||
|
}
|
||||||
|
|
||||||
|
var b uint64
|
||||||
|
// we already checked the first byte
|
||||||
|
x = uint64(buf[i]) - 0x80
|
||||||
|
i++
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 7
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
x -= 0x80 << 7
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 14
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
x -= 0x80 << 14
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 21
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
x -= 0x80 << 21
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 28
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
x -= 0x80 << 28
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 35
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
x -= 0x80 << 35
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 42
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
x -= 0x80 << 42
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 49
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
x -= 0x80 << 49
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 56
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
x -= 0x80 << 56
|
||||||
|
|
||||||
|
b = uint64(buf[i])
|
||||||
|
i++
|
||||||
|
x += b << 63
|
||||||
|
if b&0x80 == 0 {
|
||||||
|
goto done
|
||||||
|
}
|
||||||
|
// x -= 0x80 << 63 // Always zero.
|
||||||
|
|
||||||
|
return 0, errOverflow
|
||||||
|
|
||||||
|
done:
|
||||||
|
p.index = i
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeFixed64 reads a 64-bit integer from the Buffer.
|
||||||
|
// This is the format for the
|
||||||
|
// fixed64, sfixed64, and double protocol buffer types.
|
||||||
|
func (p *Buffer) DecodeFixed64() (x uint64, err error) {
|
||||||
|
// x, err already 0
|
||||||
|
i := p.index + 8
|
||||||
|
if i < 0 || i > len(p.buf) {
|
||||||
|
err = io.ErrUnexpectedEOF
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.index = i
|
||||||
|
|
||||||
|
x = uint64(p.buf[i-8])
|
||||||
|
x |= uint64(p.buf[i-7]) << 8
|
||||||
|
x |= uint64(p.buf[i-6]) << 16
|
||||||
|
x |= uint64(p.buf[i-5]) << 24
|
||||||
|
x |= uint64(p.buf[i-4]) << 32
|
||||||
|
x |= uint64(p.buf[i-3]) << 40
|
||||||
|
x |= uint64(p.buf[i-2]) << 48
|
||||||
|
x |= uint64(p.buf[i-1]) << 56
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeFixed32 reads a 32-bit integer from the Buffer.
|
||||||
|
// This is the format for the
|
||||||
|
// fixed32, sfixed32, and float protocol buffer types.
|
||||||
|
func (p *Buffer) DecodeFixed32() (x uint64, err error) {
|
||||||
|
// x, err already 0
|
||||||
|
i := p.index + 4
|
||||||
|
if i < 0 || i > len(p.buf) {
|
||||||
|
err = io.ErrUnexpectedEOF
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.index = i
|
||||||
|
|
||||||
|
x = uint64(p.buf[i-4])
|
||||||
|
x |= uint64(p.buf[i-3]) << 8
|
||||||
|
x |= uint64(p.buf[i-2]) << 16
|
||||||
|
x |= uint64(p.buf[i-1]) << 24
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeZigzag64 reads a zigzag-encoded 64-bit integer
|
||||||
|
// from the Buffer.
|
||||||
|
// This is the format used for the sint64 protocol buffer type.
|
||||||
|
func (p *Buffer) DecodeZigzag64() (x uint64, err error) {
|
||||||
|
x, err = p.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeZigzag32 reads a zigzag-encoded 32-bit integer
|
||||||
|
// from the Buffer.
|
||||||
|
// This is the format used for the sint32 protocol buffer type.
|
||||||
|
func (p *Buffer) DecodeZigzag32() (x uint64, err error) {
|
||||||
|
x, err = p.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are not ValueDecoders: they produce an array of bytes or a string.
|
||||||
|
// bytes, embedded messages
|
||||||
|
|
||||||
|
// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
|
||||||
|
// This is the format used for the bytes protocol buffer
|
||||||
|
// type and for embedded messages.
|
||||||
|
func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) {
|
||||||
|
n, err := p.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nb := int(n)
|
||||||
|
if nb < 0 {
|
||||||
|
return nil, fmt.Errorf("proto: bad byte length %d", nb)
|
||||||
|
}
|
||||||
|
end := p.index + nb
|
||||||
|
if end < p.index || end > len(p.buf) {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
if !alloc {
|
||||||
|
// todo: check if can get more uses of alloc=false
|
||||||
|
buf = p.buf[p.index:end]
|
||||||
|
p.index += nb
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = make([]byte, nb)
|
||||||
|
copy(buf, p.buf[p.index:])
|
||||||
|
p.index += nb
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeStringBytes reads an encoded string from the Buffer.
|
||||||
|
// This is the format used for the proto2 string type.
|
||||||
|
func (p *Buffer) DecodeStringBytes() (s string, err error) {
|
||||||
|
buf, err := p.DecodeRawBytes(false)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
|
||||||
|
// If the protocol buffer has extensions, and the field matches, add it as an extension.
|
||||||
|
// Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
|
||||||
|
func (o *Buffer) skipAndSave(t reflect.Type, tag, wire int, base structPointer, unrecField field) error {
|
||||||
|
oi := o.index
|
||||||
|
|
||||||
|
err := o.skip(t, tag, wire)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !unrecField.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr := structPointer_Bytes(base, unrecField)
|
||||||
|
|
||||||
|
// Add the skipped field to struct field
|
||||||
|
obuf := o.buf
|
||||||
|
|
||||||
|
o.buf = *ptr
|
||||||
|
o.EncodeVarint(uint64(tag<<3 | wire))
|
||||||
|
*ptr = append(o.buf, obuf[oi:o.index]...)
|
||||||
|
|
||||||
|
o.buf = obuf
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
|
||||||
|
func (o *Buffer) skip(t reflect.Type, tag, wire int) error {
|
||||||
|
|
||||||
|
var u uint64
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch wire {
|
||||||
|
case WireVarint:
|
||||||
|
_, err = o.DecodeVarint()
|
||||||
|
case WireFixed64:
|
||||||
|
_, err = o.DecodeFixed64()
|
||||||
|
case WireBytes:
|
||||||
|
_, err = o.DecodeRawBytes(false)
|
||||||
|
case WireFixed32:
|
||||||
|
_, err = o.DecodeFixed32()
|
||||||
|
case WireStartGroup:
|
||||||
|
for {
|
||||||
|
u, err = o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fwire := int(u & 0x7)
|
||||||
|
if fwire == WireEndGroup {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ftag := int(u >> 3)
|
||||||
|
err = o.skip(t, ftag, fwire)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("proto: can't skip unknown wire type %d for %s", wire, t)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshaler is the interface representing objects that can
|
||||||
|
// unmarshal themselves. The method should reset the receiver before
|
||||||
|
// decoding starts. The argument points to data that may be
|
||||||
|
// overwritten, so implementations should not keep references to the
|
||||||
|
// buffer.
|
||||||
|
type Unmarshaler interface {
|
||||||
|
Unmarshal([]byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal parses the protocol buffer representation in buf and places the
|
||||||
|
// decoded result in pb. If the struct underlying pb does not match
|
||||||
|
// the data in buf, the results can be unpredictable.
|
||||||
|
//
|
||||||
|
// Unmarshal resets pb before starting to unmarshal, so any
|
||||||
|
// existing data in pb is always removed. Use UnmarshalMerge
|
||||||
|
// to preserve and append to existing data.
|
||||||
|
func Unmarshal(buf []byte, pb Message) error {
|
||||||
|
pb.Reset()
|
||||||
|
return UnmarshalMerge(buf, pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMerge parses the protocol buffer representation in buf and
|
||||||
|
// writes the decoded result to pb. If the struct underlying pb does not match
|
||||||
|
// the data in buf, the results can be unpredictable.
|
||||||
|
//
|
||||||
|
// UnmarshalMerge merges into existing data in pb.
|
||||||
|
// Most code should use Unmarshal instead.
|
||||||
|
func UnmarshalMerge(buf []byte, pb Message) error {
|
||||||
|
// If the object can unmarshal itself, let it.
|
||||||
|
if u, ok := pb.(Unmarshaler); ok {
|
||||||
|
return u.Unmarshal(buf)
|
||||||
|
}
|
||||||
|
return NewBuffer(buf).Unmarshal(pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeMessage reads a count-delimited message from the Buffer.
|
||||||
|
func (p *Buffer) DecodeMessage(pb Message) error {
|
||||||
|
enc, err := p.DecodeRawBytes(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return NewBuffer(enc).Unmarshal(pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeGroup reads a tag-delimited group from the Buffer.
|
||||||
|
func (p *Buffer) DecodeGroup(pb Message) error {
|
||||||
|
typ, base, err := getbase(pb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal parses the protocol buffer representation in the
|
||||||
|
// Buffer and places the decoded result in pb. If the struct
|
||||||
|
// underlying pb does not match the data in the buffer, the results can be
|
||||||
|
// unpredictable.
|
||||||
|
//
|
||||||
|
// Unlike proto.Unmarshal, this does not reset pb before starting to unmarshal.
|
||||||
|
func (p *Buffer) Unmarshal(pb Message) error {
|
||||||
|
// If the object can unmarshal itself, let it.
|
||||||
|
if u, ok := pb.(Unmarshaler); ok {
|
||||||
|
err := u.Unmarshal(p.buf[p.index:])
|
||||||
|
p.index = len(p.buf)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
typ, base, err := getbase(pb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), false, base)
|
||||||
|
|
||||||
|
if collectStats {
|
||||||
|
stats.Decode++
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshalType does the work of unmarshaling a structure.
|
||||||
|
func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error {
|
||||||
|
var state errorState
|
||||||
|
required, reqFields := prop.reqCount, uint64(0)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for err == nil && o.index < len(o.buf) {
|
||||||
|
oi := o.index
|
||||||
|
var u uint64
|
||||||
|
u, err = o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
wire := int(u & 0x7)
|
||||||
|
if wire == WireEndGroup {
|
||||||
|
if is_group {
|
||||||
|
if required > 0 {
|
||||||
|
// Not enough information to determine the exact field.
|
||||||
|
// (See below.)
|
||||||
|
return &RequiredNotSetError{"{Unknown}"}
|
||||||
|
}
|
||||||
|
return nil // input is satisfied
|
||||||
|
}
|
||||||
|
return fmt.Errorf("proto: %s: wiretype end group for non-group", st)
|
||||||
|
}
|
||||||
|
tag := int(u >> 3)
|
||||||
|
if tag <= 0 {
|
||||||
|
return fmt.Errorf("proto: %s: illegal tag %d (wire type %d)", st, tag, wire)
|
||||||
|
}
|
||||||
|
fieldnum, ok := prop.decoderTags.get(tag)
|
||||||
|
if !ok {
|
||||||
|
// Maybe it's an extension?
|
||||||
|
if prop.extendable {
|
||||||
|
if e, _ := extendable(structPointer_Interface(base, st)); isExtensionField(e, int32(tag)) {
|
||||||
|
if err = o.skip(st, tag, wire); err == nil {
|
||||||
|
extmap := e.extensionsWrite()
|
||||||
|
ext := extmap[int32(tag)] // may be missing
|
||||||
|
ext.enc = append(ext.enc, o.buf[oi:o.index]...)
|
||||||
|
extmap[int32(tag)] = ext
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Maybe it's a oneof?
|
||||||
|
if prop.oneofUnmarshaler != nil {
|
||||||
|
m := structPointer_Interface(base, st).(Message)
|
||||||
|
// First return value indicates whether tag is a oneof field.
|
||||||
|
ok, err = prop.oneofUnmarshaler(m, tag, wire, o)
|
||||||
|
if err == ErrInternalBadWireType {
|
||||||
|
// Map the error to something more descriptive.
|
||||||
|
// Do the formatting here to save generated code space.
|
||||||
|
err = fmt.Errorf("bad wiretype for oneof field in %T", m)
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = o.skipAndSave(st, tag, wire, base, prop.unrecField)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p := prop.Prop[fieldnum]
|
||||||
|
|
||||||
|
if p.dec == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no protobuf decoder for %s.%s\n", st, st.Field(fieldnum).Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dec := p.dec
|
||||||
|
if wire != WireStartGroup && wire != p.WireType {
|
||||||
|
if wire == WireBytes && p.packedDec != nil {
|
||||||
|
// a packable field
|
||||||
|
dec = p.packedDec
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("proto: bad wiretype for field %s.%s: got wiretype %d, want %d", st, st.Field(fieldnum).Name, wire, p.WireType)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decErr := dec(o, p, base)
|
||||||
|
if decErr != nil && !state.shouldContinue(decErr, p) {
|
||||||
|
err = decErr
|
||||||
|
}
|
||||||
|
if err == nil && p.Required {
|
||||||
|
// Successfully decoded a required field.
|
||||||
|
if tag <= 64 {
|
||||||
|
// use bitmap for fields 1-64 to catch field reuse.
|
||||||
|
var mask uint64 = 1 << uint64(tag-1)
|
||||||
|
if reqFields&mask == 0 {
|
||||||
|
// new required field
|
||||||
|
reqFields |= mask
|
||||||
|
required--
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is imprecise. It can be fooled by a required field
|
||||||
|
// with a tag > 64 that is encoded twice; that's very rare.
|
||||||
|
// A fully correct implementation would require allocating
|
||||||
|
// a data structure, which we would like to avoid.
|
||||||
|
required--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
if is_group {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
if state.err != nil {
|
||||||
|
return state.err
|
||||||
|
}
|
||||||
|
if required > 0 {
|
||||||
|
// Not enough information to determine the exact field. If we use extra
|
||||||
|
// CPU, we could determine the field only if the missing required field
|
||||||
|
// has a tag <= 64 and we check reqFields.
|
||||||
|
return &RequiredNotSetError{"{Unknown}"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Individual type decoders
|
||||||
|
// For each,
|
||||||
|
// u is the decoded value,
|
||||||
|
// v is a pointer to the field (pointer) in the struct
|
||||||
|
|
||||||
|
// Sizes of the pools to allocate inside the Buffer.
|
||||||
|
// The goal is modest amortization and allocation
|
||||||
|
// on at least 16-byte boundaries.
|
||||||
|
const (
|
||||||
|
boolPoolSize = 16
|
||||||
|
uint32PoolSize = 8
|
||||||
|
uint64PoolSize = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decode a bool.
|
||||||
|
func (o *Buffer) dec_bool(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(o.bools) == 0 {
|
||||||
|
o.bools = make([]bool, boolPoolSize)
|
||||||
|
}
|
||||||
|
o.bools[0] = u != 0
|
||||||
|
*structPointer_Bool(base, p.field) = &o.bools[0]
|
||||||
|
o.bools = o.bools[1:]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Buffer) dec_proto3_bool(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*structPointer_BoolVal(base, p.field) = u != 0
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode an int32.
|
||||||
|
func (o *Buffer) dec_int32(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
word32_Set(structPointer_Word32(base, p.field), o, uint32(u))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Buffer) dec_proto3_int32(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
word32Val_Set(structPointer_Word32Val(base, p.field), uint32(u))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode an int64.
|
||||||
|
func (o *Buffer) dec_int64(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
word64_Set(structPointer_Word64(base, p.field), o, u)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Buffer) dec_proto3_int64(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
word64Val_Set(structPointer_Word64Val(base, p.field), o, u)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a string.
|
||||||
|
func (o *Buffer) dec_string(p *Properties, base structPointer) error {
|
||||||
|
s, err := o.DecodeStringBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*structPointer_String(base, p.field) = &s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Buffer) dec_proto3_string(p *Properties, base structPointer) error {
|
||||||
|
s, err := o.DecodeStringBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*structPointer_StringVal(base, p.field) = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bytes ([]byte).
|
||||||
|
func (o *Buffer) dec_slice_byte(p *Properties, base structPointer) error {
|
||||||
|
b, err := o.DecodeRawBytes(true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*structPointer_Bytes(base, p.field) = b
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bools ([]bool).
|
||||||
|
func (o *Buffer) dec_slice_bool(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v := structPointer_BoolSlice(base, p.field)
|
||||||
|
*v = append(*v, u != 0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of bools ([]bool) in packed format.
|
||||||
|
func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error {
|
||||||
|
v := structPointer_BoolSlice(base, p.field)
|
||||||
|
|
||||||
|
nn, err := o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nb := int(nn) // number of bytes of encoded bools
|
||||||
|
fin := o.index + nb
|
||||||
|
if fin < o.index {
|
||||||
|
return errOverflow
|
||||||
|
}
|
||||||
|
|
||||||
|
y := *v
|
||||||
|
for o.index < fin {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
y = append(y, u != 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
*v = y
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of int32s ([]int32).
|
||||||
|
func (o *Buffer) dec_slice_int32(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
structPointer_Word32Slice(base, p.field).Append(uint32(u))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of int32s ([]int32) in packed format.
|
||||||
|
func (o *Buffer) dec_slice_packed_int32(p *Properties, base structPointer) error {
|
||||||
|
v := structPointer_Word32Slice(base, p.field)
|
||||||
|
|
||||||
|
nn, err := o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nb := int(nn) // number of bytes of encoded int32s
|
||||||
|
|
||||||
|
fin := o.index + nb
|
||||||
|
if fin < o.index {
|
||||||
|
return errOverflow
|
||||||
|
}
|
||||||
|
for o.index < fin {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Append(uint32(u))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of int64s ([]int64).
|
||||||
|
func (o *Buffer) dec_slice_int64(p *Properties, base structPointer) error {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
structPointer_Word64Slice(base, p.field).Append(u)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of int64s ([]int64) in packed format.
|
||||||
|
func (o *Buffer) dec_slice_packed_int64(p *Properties, base structPointer) error {
|
||||||
|
v := structPointer_Word64Slice(base, p.field)
|
||||||
|
|
||||||
|
nn, err := o.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
nb := int(nn) // number of bytes of encoded int64s
|
||||||
|
|
||||||
|
fin := o.index + nb
|
||||||
|
if fin < o.index {
|
||||||
|
return errOverflow
|
||||||
|
}
|
||||||
|
for o.index < fin {
|
||||||
|
u, err := p.valDec(o)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Append(u)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of strings ([]string).
|
||||||
|
func (o *Buffer) dec_slice_string(p *Properties, base structPointer) error {
|
||||||
|
s, err := o.DecodeStringBytes()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v := structPointer_StringSlice(base, p.field)
|
||||||
|
*v = append(*v, s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of slice of bytes ([][]byte).
|
||||||
|
func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error {
|
||||||
|
b, err := o.DecodeRawBytes(true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v := structPointer_BytesSlice(base, p.field)
|
||||||
|
*v = append(*v, b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a map field.
|
||||||
|
func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
|
||||||
|
raw, err := o.DecodeRawBytes(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
oi := o.index // index at the end of this map entry
|
||||||
|
o.index -= len(raw) // move buffer back to start of map entry
|
||||||
|
|
||||||
|
mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V
|
||||||
|
if mptr.Elem().IsNil() {
|
||||||
|
mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem()))
|
||||||
|
}
|
||||||
|
v := mptr.Elem() // map[K]V
|
||||||
|
|
||||||
|
// Prepare addressable doubly-indirect placeholders for the key and value types.
|
||||||
|
// See enc_new_map for why.
|
||||||
|
keyptr := reflect.New(reflect.PtrTo(p.mtype.Key())).Elem() // addressable *K
|
||||||
|
keybase := toStructPointer(keyptr.Addr()) // **K
|
||||||
|
|
||||||
|
var valbase structPointer
|
||||||
|
var valptr reflect.Value
|
||||||
|
switch p.mtype.Elem().Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
// []byte
|
||||||
|
var dummy []byte
|
||||||
|
valptr = reflect.ValueOf(&dummy) // *[]byte
|
||||||
|
valbase = toStructPointer(valptr) // *[]byte
|
||||||
|
case reflect.Ptr:
|
||||||
|
// message; valptr is **Msg; need to allocate the intermediate pointer
|
||||||
|
valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
|
||||||
|
valptr.Set(reflect.New(valptr.Type().Elem()))
|
||||||
|
valbase = toStructPointer(valptr)
|
||||||
|
default:
|
||||||
|
// everything else
|
||||||
|
valptr = reflect.New(reflect.PtrTo(p.mtype.Elem())).Elem() // addressable *V
|
||||||
|
valbase = toStructPointer(valptr.Addr()) // **V
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode.
|
||||||
|
// This parses a restricted wire format, namely the encoding of a message
|
||||||
|
// with two fields. See enc_new_map for the format.
|
||||||
|
for o.index < oi {
|
||||||
|
// tagcode for key and value properties are always a single byte
|
||||||
|
// because they have tags 1 and 2.
|
||||||
|
tagcode := o.buf[o.index]
|
||||||
|
o.index++
|
||||||
|
switch tagcode {
|
||||||
|
case p.mkeyprop.tagcode[0]:
|
||||||
|
if err := p.mkeyprop.dec(o, p.mkeyprop, keybase); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case p.mvalprop.tagcode[0]:
|
||||||
|
if err := p.mvalprop.dec(o, p.mvalprop, valbase); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// TODO: Should we silently skip this instead?
|
||||||
|
return fmt.Errorf("proto: bad map data tag %d", raw[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyelem, valelem := keyptr.Elem(), valptr.Elem()
|
||||||
|
if !keyelem.IsValid() {
|
||||||
|
keyelem = reflect.Zero(p.mtype.Key())
|
||||||
|
}
|
||||||
|
if !valelem.IsValid() {
|
||||||
|
valelem = reflect.Zero(p.mtype.Elem())
|
||||||
|
}
|
||||||
|
|
||||||
|
v.SetMapIndex(keyelem, valelem)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a group.
|
||||||
|
func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error {
|
||||||
|
bas := structPointer_GetStructPointer(base, p.field)
|
||||||
|
if structPointer_IsNil(bas) {
|
||||||
|
// allocate new nested message
|
||||||
|
bas = toStructPointer(reflect.New(p.stype))
|
||||||
|
structPointer_SetStructPointer(base, p.field, bas)
|
||||||
|
}
|
||||||
|
return o.unmarshalType(p.stype, p.sprop, true, bas)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode an embedded message.
|
||||||
|
func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err error) {
|
||||||
|
raw, e := o.DecodeRawBytes(false)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
bas := structPointer_GetStructPointer(base, p.field)
|
||||||
|
if structPointer_IsNil(bas) {
|
||||||
|
// allocate new nested message
|
||||||
|
bas = toStructPointer(reflect.New(p.stype))
|
||||||
|
structPointer_SetStructPointer(base, p.field, bas)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object can unmarshal itself, let it.
|
||||||
|
if p.isUnmarshaler {
|
||||||
|
iv := structPointer_Interface(bas, p.stype)
|
||||||
|
return iv.(Unmarshaler).Unmarshal(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
obuf := o.buf
|
||||||
|
oi := o.index
|
||||||
|
o.buf = raw
|
||||||
|
o.index = 0
|
||||||
|
|
||||||
|
err = o.unmarshalType(p.stype, p.sprop, false, bas)
|
||||||
|
o.buf = obuf
|
||||||
|
o.index = oi
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of embedded messages.
|
||||||
|
func (o *Buffer) dec_slice_struct_message(p *Properties, base structPointer) error {
|
||||||
|
return o.dec_slice_struct(p, false, base)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of embedded groups.
|
||||||
|
func (o *Buffer) dec_slice_struct_group(p *Properties, base structPointer) error {
|
||||||
|
return o.dec_slice_struct(p, true, base)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode a slice of structs ([]*struct).
|
||||||
|
func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base structPointer) error {
|
||||||
|
v := reflect.New(p.stype)
|
||||||
|
bas := toStructPointer(v)
|
||||||
|
structPointer_StructPointerSlice(base, p.field).Append(bas)
|
||||||
|
|
||||||
|
if is_group {
|
||||||
|
err := o.unmarshalType(p.stype, p.sprop, is_group, bas)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := o.DecodeRawBytes(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the object can unmarshal itself, let it.
|
||||||
|
if p.isUnmarshaler {
|
||||||
|
iv := v.Interface()
|
||||||
|
return iv.(Unmarshaler).Unmarshal(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
obuf := o.buf
|
||||||
|
oi := o.index
|
||||||
|
o.buf = raw
|
||||||
|
o.index = 0
|
||||||
|
|
||||||
|
err = o.unmarshalType(p.stype, p.sprop, is_group, bas)
|
||||||
|
|
||||||
|
o.buf = obuf
|
||||||
|
o.index = oi
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
1362
vendor/github.com/golang/protobuf/proto/encode.go
generated
vendored
Normal file
1362
vendor/github.com/golang/protobuf/proto/encode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
300
vendor/github.com/golang/protobuf/proto/equal.go
generated
vendored
Normal file
300
vendor/github.com/golang/protobuf/proto/equal.go
generated
vendored
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
// Protocol buffer comparison.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Equal returns true iff protocol buffers a and b are equal.
|
||||||
|
The arguments must both be pointers to protocol buffer structs.
|
||||||
|
|
||||||
|
Equality is defined in this way:
|
||||||
|
- Two messages are equal iff they are the same type,
|
||||||
|
corresponding fields are equal, unknown field sets
|
||||||
|
are equal, and extensions sets are equal.
|
||||||
|
- Two set scalar fields are equal iff their values are equal.
|
||||||
|
If the fields are of a floating-point type, remember that
|
||||||
|
NaN != x for all x, including NaN. If the message is defined
|
||||||
|
in a proto3 .proto file, fields are not "set"; specifically,
|
||||||
|
zero length proto3 "bytes" fields are equal (nil == {}).
|
||||||
|
- Two repeated fields are equal iff their lengths are the same,
|
||||||
|
and their corresponding elements are equal. Note a "bytes" field,
|
||||||
|
although represented by []byte, is not a repeated field and the
|
||||||
|
rule for the scalar fields described above applies.
|
||||||
|
- Two unset fields are equal.
|
||||||
|
- Two unknown field sets are equal if their current
|
||||||
|
encoded state is equal.
|
||||||
|
- Two extension sets are equal iff they have corresponding
|
||||||
|
elements that are pairwise equal.
|
||||||
|
- Two map fields are equal iff their lengths are the same,
|
||||||
|
and they contain the same set of elements. Zero-length map
|
||||||
|
fields are equal.
|
||||||
|
- Every other combination of things are not equal.
|
||||||
|
|
||||||
|
The return value is undefined if a and b are not protocol buffers.
|
||||||
|
*/
|
||||||
|
func Equal(a, b Message) bool {
|
||||||
|
if a == nil || b == nil {
|
||||||
|
return a == b
|
||||||
|
}
|
||||||
|
v1, v2 := reflect.ValueOf(a), reflect.ValueOf(b)
|
||||||
|
if v1.Type() != v2.Type() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if v1.Kind() == reflect.Ptr {
|
||||||
|
if v1.IsNil() {
|
||||||
|
return v2.IsNil()
|
||||||
|
}
|
||||||
|
if v2.IsNil() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
v1, v2 = v1.Elem(), v2.Elem()
|
||||||
|
}
|
||||||
|
if v1.Kind() != reflect.Struct {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return equalStruct(v1, v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// v1 and v2 are known to have the same type.
|
||||||
|
func equalStruct(v1, v2 reflect.Value) bool {
|
||||||
|
sprop := GetProperties(v1.Type())
|
||||||
|
for i := 0; i < v1.NumField(); i++ {
|
||||||
|
f := v1.Type().Field(i)
|
||||||
|
if strings.HasPrefix(f.Name, "XXX_") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
f1, f2 := v1.Field(i), v2.Field(i)
|
||||||
|
if f.Type.Kind() == reflect.Ptr {
|
||||||
|
if n1, n2 := f1.IsNil(), f2.IsNil(); n1 && n2 {
|
||||||
|
// both unset
|
||||||
|
continue
|
||||||
|
} else if n1 != n2 {
|
||||||
|
// set/unset mismatch
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
b1, ok := f1.Interface().(raw)
|
||||||
|
if ok {
|
||||||
|
b2 := f2.Interface().(raw)
|
||||||
|
// RawMessage
|
||||||
|
if !bytes.Equal(b1.Bytes(), b2.Bytes()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
f1, f2 = f1.Elem(), f2.Elem()
|
||||||
|
}
|
||||||
|
if !equalAny(f1, f2, sprop.Prop[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if em1 := v1.FieldByName("XXX_InternalExtensions"); em1.IsValid() {
|
||||||
|
em2 := v2.FieldByName("XXX_InternalExtensions")
|
||||||
|
if !equalExtensions(v1.Type(), em1.Interface().(XXX_InternalExtensions), em2.Interface().(XXX_InternalExtensions)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if em1 := v1.FieldByName("XXX_extensions"); em1.IsValid() {
|
||||||
|
em2 := v2.FieldByName("XXX_extensions")
|
||||||
|
if !equalExtMap(v1.Type(), em1.Interface().(map[int32]Extension), em2.Interface().(map[int32]Extension)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uf := v1.FieldByName("XXX_unrecognized")
|
||||||
|
if !uf.IsValid() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
u1 := uf.Bytes()
|
||||||
|
u2 := v2.FieldByName("XXX_unrecognized").Bytes()
|
||||||
|
if !bytes.Equal(u1, u2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// v1 and v2 are known to have the same type.
|
||||||
|
// prop may be nil.
|
||||||
|
func equalAny(v1, v2 reflect.Value, prop *Properties) bool {
|
||||||
|
if v1.Type() == protoMessageType {
|
||||||
|
m1, _ := v1.Interface().(Message)
|
||||||
|
m2, _ := v2.Interface().(Message)
|
||||||
|
return Equal(m1, m2)
|
||||||
|
}
|
||||||
|
switch v1.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return v1.Bool() == v2.Bool()
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v1.Float() == v2.Float()
|
||||||
|
case reflect.Int32, reflect.Int64:
|
||||||
|
return v1.Int() == v2.Int()
|
||||||
|
case reflect.Interface:
|
||||||
|
// Probably a oneof field; compare the inner values.
|
||||||
|
n1, n2 := v1.IsNil(), v2.IsNil()
|
||||||
|
if n1 || n2 {
|
||||||
|
return n1 == n2
|
||||||
|
}
|
||||||
|
e1, e2 := v1.Elem(), v2.Elem()
|
||||||
|
if e1.Type() != e2.Type() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return equalAny(e1, e2, nil)
|
||||||
|
case reflect.Map:
|
||||||
|
if v1.Len() != v2.Len() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, key := range v1.MapKeys() {
|
||||||
|
val2 := v2.MapIndex(key)
|
||||||
|
if !val2.IsValid() {
|
||||||
|
// This key was not found in the second map.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !equalAny(v1.MapIndex(key), val2, nil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.Ptr:
|
||||||
|
// Maps may have nil values in them, so check for nil.
|
||||||
|
if v1.IsNil() && v2.IsNil() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if v1.IsNil() != v2.IsNil() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return equalAny(v1.Elem(), v2.Elem(), prop)
|
||||||
|
case reflect.Slice:
|
||||||
|
if v1.Type().Elem().Kind() == reflect.Uint8 {
|
||||||
|
// short circuit: []byte
|
||||||
|
|
||||||
|
// Edge case: if this is in a proto3 message, a zero length
|
||||||
|
// bytes field is considered the zero value.
|
||||||
|
if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if v1.IsNil() != v2.IsNil() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return bytes.Equal(v1.Interface().([]byte), v2.Interface().([]byte))
|
||||||
|
}
|
||||||
|
|
||||||
|
if v1.Len() != v2.Len() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := 0; i < v1.Len(); i++ {
|
||||||
|
if !equalAny(v1.Index(i), v2.Index(i), prop) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case reflect.String:
|
||||||
|
return v1.Interface().(string) == v2.Interface().(string)
|
||||||
|
case reflect.Struct:
|
||||||
|
return equalStruct(v1, v2)
|
||||||
|
case reflect.Uint32, reflect.Uint64:
|
||||||
|
return v1.Uint() == v2.Uint()
|
||||||
|
}
|
||||||
|
|
||||||
|
// unknown type, so not a protocol buffer
|
||||||
|
log.Printf("proto: don't know how to compare %v", v1)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// base is the struct type that the extensions are based on.
|
||||||
|
// x1 and x2 are InternalExtensions.
|
||||||
|
func equalExtensions(base reflect.Type, x1, x2 XXX_InternalExtensions) bool {
|
||||||
|
em1, _ := x1.extensionsRead()
|
||||||
|
em2, _ := x2.extensionsRead()
|
||||||
|
return equalExtMap(base, em1, em2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalExtMap(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
||||||
|
if len(em1) != len(em2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for extNum, e1 := range em1 {
|
||||||
|
e2, ok := em2[extNum]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
m1, m2 := e1.value, e2.value
|
||||||
|
|
||||||
|
if m1 != nil && m2 != nil {
|
||||||
|
// Both are unencoded.
|
||||||
|
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// At least one is encoded. To do a semantically correct comparison
|
||||||
|
// we need to unmarshal them first.
|
||||||
|
var desc *ExtensionDesc
|
||||||
|
if m := extensionMaps[base]; m != nil {
|
||||||
|
desc = m[extNum]
|
||||||
|
}
|
||||||
|
if desc == nil {
|
||||||
|
log.Printf("proto: don't know how to compare extension %d of %v", extNum, base)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if m1 == nil {
|
||||||
|
m1, err = decodeExtension(e1.enc, desc)
|
||||||
|
}
|
||||||
|
if m2 == nil && err == nil {
|
||||||
|
m2, err = decodeExtension(e2.enc, desc)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// The encoded form is invalid.
|
||||||
|
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
587
vendor/github.com/golang/protobuf/proto/extensions.go
generated
vendored
Normal file
587
vendor/github.com/golang/protobuf/proto/extensions.go
generated
vendored
Normal file
|
@ -0,0 +1,587 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types and routines for supporting protocol buffer extensions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrMissingExtension is the error returned by GetExtension if the named extension is not in the message.
|
||||||
|
var ErrMissingExtension = errors.New("proto: missing extension")
|
||||||
|
|
||||||
|
// ExtensionRange represents a range of message extensions for a protocol buffer.
|
||||||
|
// Used in code generated by the protocol compiler.
|
||||||
|
type ExtensionRange struct {
|
||||||
|
Start, End int32 // both inclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
// extendableProto is an interface implemented by any protocol buffer generated by the current
|
||||||
|
// proto compiler that may be extended.
|
||||||
|
type extendableProto interface {
|
||||||
|
Message
|
||||||
|
ExtensionRangeArray() []ExtensionRange
|
||||||
|
extensionsWrite() map[int32]Extension
|
||||||
|
extensionsRead() (map[int32]Extension, sync.Locker)
|
||||||
|
}
|
||||||
|
|
||||||
|
// extendableProtoV1 is an interface implemented by a protocol buffer generated by the previous
|
||||||
|
// version of the proto compiler that may be extended.
|
||||||
|
type extendableProtoV1 interface {
|
||||||
|
Message
|
||||||
|
ExtensionRangeArray() []ExtensionRange
|
||||||
|
ExtensionMap() map[int32]Extension
|
||||||
|
}
|
||||||
|
|
||||||
|
// extensionAdapter is a wrapper around extendableProtoV1 that implements extendableProto.
|
||||||
|
type extensionAdapter struct {
|
||||||
|
extendableProtoV1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e extensionAdapter) extensionsWrite() map[int32]Extension {
|
||||||
|
return e.ExtensionMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e extensionAdapter) extensionsRead() (map[int32]Extension, sync.Locker) {
|
||||||
|
return e.ExtensionMap(), notLocker{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// notLocker is a sync.Locker whose Lock and Unlock methods are nops.
|
||||||
|
type notLocker struct{}
|
||||||
|
|
||||||
|
func (n notLocker) Lock() {}
|
||||||
|
func (n notLocker) Unlock() {}
|
||||||
|
|
||||||
|
// extendable returns the extendableProto interface for the given generated proto message.
|
||||||
|
// If the proto message has the old extension format, it returns a wrapper that implements
|
||||||
|
// the extendableProto interface.
|
||||||
|
func extendable(p interface{}) (extendableProto, bool) {
|
||||||
|
if ep, ok := p.(extendableProto); ok {
|
||||||
|
return ep, ok
|
||||||
|
}
|
||||||
|
if ep, ok := p.(extendableProtoV1); ok {
|
||||||
|
return extensionAdapter{ep}, ok
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX_InternalExtensions is an internal representation of proto extensions.
|
||||||
|
//
|
||||||
|
// Each generated message struct type embeds an anonymous XXX_InternalExtensions field,
|
||||||
|
// thus gaining the unexported 'extensions' method, which can be called only from the proto package.
|
||||||
|
//
|
||||||
|
// The methods of XXX_InternalExtensions are not concurrency safe in general,
|
||||||
|
// but calls to logically read-only methods such as has and get may be executed concurrently.
|
||||||
|
type XXX_InternalExtensions struct {
|
||||||
|
// The struct must be indirect so that if a user inadvertently copies a
|
||||||
|
// generated message and its embedded XXX_InternalExtensions, they
|
||||||
|
// avoid the mayhem of a copied mutex.
|
||||||
|
//
|
||||||
|
// The mutex serializes all logically read-only operations to p.extensionMap.
|
||||||
|
// It is up to the client to ensure that write operations to p.extensionMap are
|
||||||
|
// mutually exclusive with other accesses.
|
||||||
|
p *struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
extensionMap map[int32]Extension
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// extensionsWrite returns the extension map, creating it on first use.
|
||||||
|
func (e *XXX_InternalExtensions) extensionsWrite() map[int32]Extension {
|
||||||
|
if e.p == nil {
|
||||||
|
e.p = new(struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
extensionMap map[int32]Extension
|
||||||
|
})
|
||||||
|
e.p.extensionMap = make(map[int32]Extension)
|
||||||
|
}
|
||||||
|
return e.p.extensionMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// extensionsRead returns the extensions map for read-only use. It may be nil.
|
||||||
|
// The caller must hold the returned mutex's lock when accessing Elements within the map.
|
||||||
|
func (e *XXX_InternalExtensions) extensionsRead() (map[int32]Extension, sync.Locker) {
|
||||||
|
if e.p == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return e.p.extensionMap, &e.p.mu
|
||||||
|
}
|
||||||
|
|
||||||
|
var extendableProtoType = reflect.TypeOf((*extendableProto)(nil)).Elem()
|
||||||
|
var extendableProtoV1Type = reflect.TypeOf((*extendableProtoV1)(nil)).Elem()
|
||||||
|
|
||||||
|
// ExtensionDesc represents an extension specification.
|
||||||
|
// Used in generated code from the protocol compiler.
|
||||||
|
type ExtensionDesc struct {
|
||||||
|
ExtendedType Message // nil pointer to the type that is being extended
|
||||||
|
ExtensionType interface{} // nil pointer to the extension type
|
||||||
|
Field int32 // field number
|
||||||
|
Name string // fully-qualified name of extension, for text formatting
|
||||||
|
Tag string // protobuf tag style
|
||||||
|
Filename string // name of the file in which the extension is defined
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ed *ExtensionDesc) repeated() bool {
|
||||||
|
t := reflect.TypeOf(ed.ExtensionType)
|
||||||
|
return t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extension represents an extension in a message.
|
||||||
|
type Extension struct {
|
||||||
|
// When an extension is stored in a message using SetExtension
|
||||||
|
// only desc and value are set. When the message is marshaled
|
||||||
|
// enc will be set to the encoded form of the message.
|
||||||
|
//
|
||||||
|
// When a message is unmarshaled and contains extensions, each
|
||||||
|
// extension will have only enc set. When such an extension is
|
||||||
|
// accessed using GetExtension (or GetExtensions) desc and value
|
||||||
|
// will be set.
|
||||||
|
desc *ExtensionDesc
|
||||||
|
value interface{}
|
||||||
|
enc []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRawExtension is for testing only.
|
||||||
|
func SetRawExtension(base Message, id int32, b []byte) {
|
||||||
|
epb, ok := extendable(base)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
extmap := epb.extensionsWrite()
|
||||||
|
extmap[id] = Extension{enc: b}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isExtensionField returns true iff the given field number is in an extension range.
|
||||||
|
func isExtensionField(pb extendableProto, field int32) bool {
|
||||||
|
for _, er := range pb.ExtensionRangeArray() {
|
||||||
|
if er.Start <= field && field <= er.End {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkExtensionTypes checks that the given extension is valid for pb.
|
||||||
|
func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
|
||||||
|
var pbi interface{} = pb
|
||||||
|
// Check the extended type.
|
||||||
|
if ea, ok := pbi.(extensionAdapter); ok {
|
||||||
|
pbi = ea.extendableProtoV1
|
||||||
|
}
|
||||||
|
if a, b := reflect.TypeOf(pbi), reflect.TypeOf(extension.ExtendedType); a != b {
|
||||||
|
return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String())
|
||||||
|
}
|
||||||
|
// Check the range.
|
||||||
|
if !isExtensionField(pb, extension.Field) {
|
||||||
|
return errors.New("proto: bad extension number; not in declared ranges")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// extPropKey is sufficient to uniquely identify an extension.
|
||||||
|
type extPropKey struct {
|
||||||
|
base reflect.Type
|
||||||
|
field int32
|
||||||
|
}
|
||||||
|
|
||||||
|
var extProp = struct {
|
||||||
|
sync.RWMutex
|
||||||
|
m map[extPropKey]*Properties
|
||||||
|
}{
|
||||||
|
m: make(map[extPropKey]*Properties),
|
||||||
|
}
|
||||||
|
|
||||||
|
func extensionProperties(ed *ExtensionDesc) *Properties {
|
||||||
|
key := extPropKey{base: reflect.TypeOf(ed.ExtendedType), field: ed.Field}
|
||||||
|
|
||||||
|
extProp.RLock()
|
||||||
|
if prop, ok := extProp.m[key]; ok {
|
||||||
|
extProp.RUnlock()
|
||||||
|
return prop
|
||||||
|
}
|
||||||
|
extProp.RUnlock()
|
||||||
|
|
||||||
|
extProp.Lock()
|
||||||
|
defer extProp.Unlock()
|
||||||
|
// Check again.
|
||||||
|
if prop, ok := extProp.m[key]; ok {
|
||||||
|
return prop
|
||||||
|
}
|
||||||
|
|
||||||
|
prop := new(Properties)
|
||||||
|
prop.Init(reflect.TypeOf(ed.ExtensionType), "unknown_name", ed.Tag, nil)
|
||||||
|
extProp.m[key] = prop
|
||||||
|
return prop
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode encodes any unmarshaled (unencoded) extensions in e.
|
||||||
|
func encodeExtensions(e *XXX_InternalExtensions) error {
|
||||||
|
m, mu := e.extensionsRead()
|
||||||
|
if m == nil {
|
||||||
|
return nil // fast path
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
return encodeExtensionsMap(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode encodes any unmarshaled (unencoded) extensions in e.
|
||||||
|
func encodeExtensionsMap(m map[int32]Extension) error {
|
||||||
|
for k, e := range m {
|
||||||
|
if e.value == nil || e.desc == nil {
|
||||||
|
// Extension is only in its encoded form.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't skip extensions that have an encoded form set,
|
||||||
|
// because the extension value may have been mutated after
|
||||||
|
// the last time this function was called.
|
||||||
|
|
||||||
|
et := reflect.TypeOf(e.desc.ExtensionType)
|
||||||
|
props := extensionProperties(e.desc)
|
||||||
|
|
||||||
|
p := NewBuffer(nil)
|
||||||
|
// If e.value has type T, the encoder expects a *struct{ X T }.
|
||||||
|
// Pass a *T with a zero field and hope it all works out.
|
||||||
|
x := reflect.New(et)
|
||||||
|
x.Elem().Set(reflect.ValueOf(e.value))
|
||||||
|
if err := props.enc(p, props, toStructPointer(x)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
e.enc = p.buf
|
||||||
|
m[k] = e
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func extensionsSize(e *XXX_InternalExtensions) (n int) {
|
||||||
|
m, mu := e.extensionsRead()
|
||||||
|
if m == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
return extensionsMapSize(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extensionsMapSize(m map[int32]Extension) (n int) {
|
||||||
|
for _, e := range m {
|
||||||
|
if e.value == nil || e.desc == nil {
|
||||||
|
// Extension is only in its encoded form.
|
||||||
|
n += len(e.enc)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't skip extensions that have an encoded form set,
|
||||||
|
// because the extension value may have been mutated after
|
||||||
|
// the last time this function was called.
|
||||||
|
|
||||||
|
et := reflect.TypeOf(e.desc.ExtensionType)
|
||||||
|
props := extensionProperties(e.desc)
|
||||||
|
|
||||||
|
// If e.value has type T, the encoder expects a *struct{ X T }.
|
||||||
|
// Pass a *T with a zero field and hope it all works out.
|
||||||
|
x := reflect.New(et)
|
||||||
|
x.Elem().Set(reflect.ValueOf(e.value))
|
||||||
|
n += props.size(props, toStructPointer(x))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasExtension returns whether the given extension is present in pb.
|
||||||
|
func HasExtension(pb Message, extension *ExtensionDesc) bool {
|
||||||
|
// TODO: Check types, field numbers, etc.?
|
||||||
|
epb, ok := extendable(pb)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
extmap, mu := epb.extensionsRead()
|
||||||
|
if extmap == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
_, ok = extmap[extension.Field]
|
||||||
|
mu.Unlock()
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearExtension removes the given extension from pb.
|
||||||
|
func ClearExtension(pb Message, extension *ExtensionDesc) {
|
||||||
|
epb, ok := extendable(pb)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// TODO: Check types, field numbers, etc.?
|
||||||
|
extmap := epb.extensionsWrite()
|
||||||
|
delete(extmap, extension.Field)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExtension parses and returns the given extension of pb.
|
||||||
|
// If the extension is not present and has no default value it returns ErrMissingExtension.
|
||||||
|
func GetExtension(pb Message, extension *ExtensionDesc) (interface{}, error) {
|
||||||
|
epb, ok := extendable(pb)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("proto: not an extendable proto")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkExtensionTypes(epb, extension); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
emap, mu := epb.extensionsRead()
|
||||||
|
if emap == nil {
|
||||||
|
return defaultExtensionValue(extension)
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
e, ok := emap[extension.Field]
|
||||||
|
if !ok {
|
||||||
|
// defaultExtensionValue returns the default value or
|
||||||
|
// ErrMissingExtension if there is no default.
|
||||||
|
return defaultExtensionValue(extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.value != nil {
|
||||||
|
// Already decoded. Check the descriptor, though.
|
||||||
|
if e.desc != extension {
|
||||||
|
// This shouldn't happen. If it does, it means that
|
||||||
|
// GetExtension was called twice with two different
|
||||||
|
// descriptors with the same field number.
|
||||||
|
return nil, errors.New("proto: descriptor conflict")
|
||||||
|
}
|
||||||
|
return e.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := decodeExtension(e.enc, extension)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the decoded version and drop the encoded version.
|
||||||
|
// That way it is safe to mutate what we return.
|
||||||
|
e.value = v
|
||||||
|
e.desc = extension
|
||||||
|
e.enc = nil
|
||||||
|
emap[extension.Field] = e
|
||||||
|
return e.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultExtensionValue returns the default value for extension.
|
||||||
|
// If no default for an extension is defined ErrMissingExtension is returned.
|
||||||
|
func defaultExtensionValue(extension *ExtensionDesc) (interface{}, error) {
|
||||||
|
t := reflect.TypeOf(extension.ExtensionType)
|
||||||
|
props := extensionProperties(extension)
|
||||||
|
|
||||||
|
sf, _, err := fieldDefault(t, props)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if sf == nil || sf.value == nil {
|
||||||
|
// There is no default value.
|
||||||
|
return nil, ErrMissingExtension
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.Kind() != reflect.Ptr {
|
||||||
|
// We do not need to return a Ptr, we can directly return sf.value.
|
||||||
|
return sf.value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to return an interface{} that is a pointer to sf.value.
|
||||||
|
value := reflect.New(t).Elem()
|
||||||
|
value.Set(reflect.New(value.Type().Elem()))
|
||||||
|
if sf.kind == reflect.Int32 {
|
||||||
|
// We may have an int32 or an enum, but the underlying data is int32.
|
||||||
|
// Since we can't set an int32 into a non int32 reflect.value directly
|
||||||
|
// set it as a int32.
|
||||||
|
value.Elem().SetInt(int64(sf.value.(int32)))
|
||||||
|
} else {
|
||||||
|
value.Elem().Set(reflect.ValueOf(sf.value))
|
||||||
|
}
|
||||||
|
return value.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeExtension decodes an extension encoded in b.
|
||||||
|
func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
||||||
|
o := NewBuffer(b)
|
||||||
|
|
||||||
|
t := reflect.TypeOf(extension.ExtensionType)
|
||||||
|
|
||||||
|
props := extensionProperties(extension)
|
||||||
|
|
||||||
|
// t is a pointer to a struct, pointer to basic type or a slice.
|
||||||
|
// Allocate a "field" to store the pointer/slice itself; the
|
||||||
|
// pointer/slice will be stored here. We pass
|
||||||
|
// the address of this field to props.dec.
|
||||||
|
// This passes a zero field and a *t and lets props.dec
|
||||||
|
// interpret it as a *struct{ x t }.
|
||||||
|
value := reflect.New(t).Elem()
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Discard wire type and field number varint. It isn't needed.
|
||||||
|
if _, err := o.DecodeVarint(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := props.dec(o, props, toStructPointer(value.Addr())); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.index >= len(o.buf) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExtensions returns a slice of the extensions present in pb that are also listed in es.
|
||||||
|
// The returned slice has the same length as es; missing extensions will appear as nil elements.
|
||||||
|
func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
|
||||||
|
epb, ok := extendable(pb)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("proto: not an extendable proto")
|
||||||
|
}
|
||||||
|
extensions = make([]interface{}, len(es))
|
||||||
|
for i, e := range es {
|
||||||
|
extensions[i], err = GetExtension(epb, e)
|
||||||
|
if err == ErrMissingExtension {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtensionDescs returns a new slice containing pb's extension descriptors, in undefined order.
|
||||||
|
// For non-registered extensions, ExtensionDescs returns an incomplete descriptor containing
|
||||||
|
// just the Field field, which defines the extension's field number.
|
||||||
|
func ExtensionDescs(pb Message) ([]*ExtensionDesc, error) {
|
||||||
|
epb, ok := extendable(pb)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("proto: %T is not an extendable proto.Message", pb)
|
||||||
|
}
|
||||||
|
registeredExtensions := RegisteredExtensions(pb)
|
||||||
|
|
||||||
|
emap, mu := epb.extensionsRead()
|
||||||
|
if emap == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
defer mu.Unlock()
|
||||||
|
extensions := make([]*ExtensionDesc, 0, len(emap))
|
||||||
|
for extid, e := range emap {
|
||||||
|
desc := e.desc
|
||||||
|
if desc == nil {
|
||||||
|
desc = registeredExtensions[extid]
|
||||||
|
if desc == nil {
|
||||||
|
desc = &ExtensionDesc{Field: extid}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions = append(extensions, desc)
|
||||||
|
}
|
||||||
|
return extensions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetExtension sets the specified extension of pb to the specified value.
|
||||||
|
func SetExtension(pb Message, extension *ExtensionDesc, value interface{}) error {
|
||||||
|
epb, ok := extendable(pb)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("proto: not an extendable proto")
|
||||||
|
}
|
||||||
|
if err := checkExtensionTypes(epb, extension); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
typ := reflect.TypeOf(extension.ExtensionType)
|
||||||
|
if typ != reflect.TypeOf(value) {
|
||||||
|
return errors.New("proto: bad extension value type")
|
||||||
|
}
|
||||||
|
// nil extension values need to be caught early, because the
|
||||||
|
// encoder can't distinguish an ErrNil due to a nil extension
|
||||||
|
// from an ErrNil due to a missing field. Extensions are
|
||||||
|
// always optional, so the encoder would just swallow the error
|
||||||
|
// and drop all the extensions from the encoded message.
|
||||||
|
if reflect.ValueOf(value).IsNil() {
|
||||||
|
return fmt.Errorf("proto: SetExtension called with nil value of type %T", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
extmap := epb.extensionsWrite()
|
||||||
|
extmap[extension.Field] = Extension{desc: extension, value: value}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearAllExtensions clears all extensions from pb.
|
||||||
|
func ClearAllExtensions(pb Message) {
|
||||||
|
epb, ok := extendable(pb)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m := epb.extensionsWrite()
|
||||||
|
for k := range m {
|
||||||
|
delete(m, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A global registry of extensions.
|
||||||
|
// The generated code will register the generated descriptors by calling RegisterExtension.
|
||||||
|
|
||||||
|
var extensionMaps = make(map[reflect.Type]map[int32]*ExtensionDesc)
|
||||||
|
|
||||||
|
// RegisterExtension is called from the generated code.
|
||||||
|
func RegisterExtension(desc *ExtensionDesc) {
|
||||||
|
st := reflect.TypeOf(desc.ExtendedType).Elem()
|
||||||
|
m := extensionMaps[st]
|
||||||
|
if m == nil {
|
||||||
|
m = make(map[int32]*ExtensionDesc)
|
||||||
|
extensionMaps[st] = m
|
||||||
|
}
|
||||||
|
if _, ok := m[desc.Field]; ok {
|
||||||
|
panic("proto: duplicate extension registered: " + st.String() + " " + strconv.Itoa(int(desc.Field)))
|
||||||
|
}
|
||||||
|
m[desc.Field] = desc
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisteredExtensions returns a map of the registered extensions of a
|
||||||
|
// protocol buffer struct, indexed by the extension number.
|
||||||
|
// The argument pb should be a nil pointer to the struct type.
|
||||||
|
func RegisteredExtensions(pb Message) map[int32]*ExtensionDesc {
|
||||||
|
return extensionMaps[reflect.TypeOf(pb).Elem()]
|
||||||
|
}
|
897
vendor/github.com/golang/protobuf/proto/lib.go
generated
vendored
Normal file
897
vendor/github.com/golang/protobuf/proto/lib.go
generated
vendored
Normal file
|
@ -0,0 +1,897 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package proto converts data structures to and from the wire format of
|
||||||
|
protocol buffers. It works in concert with the Go source code generated
|
||||||
|
for .proto files by the protocol compiler.
|
||||||
|
|
||||||
|
A summary of the properties of the protocol buffer interface
|
||||||
|
for a protocol buffer variable v:
|
||||||
|
|
||||||
|
- Names are turned from camel_case to CamelCase for export.
|
||||||
|
- There are no methods on v to set fields; just treat
|
||||||
|
them as structure fields.
|
||||||
|
- There are getters that return a field's value if set,
|
||||||
|
and return the field's default value if unset.
|
||||||
|
The getters work even if the receiver is a nil message.
|
||||||
|
- The zero value for a struct is its correct initialization state.
|
||||||
|
All desired fields must be set before marshaling.
|
||||||
|
- A Reset() method will restore a protobuf struct to its zero state.
|
||||||
|
- Non-repeated fields are pointers to the values; nil means unset.
|
||||||
|
That is, optional or required field int32 f becomes F *int32.
|
||||||
|
- Repeated fields are slices.
|
||||||
|
- Helper functions are available to aid the setting of fields.
|
||||||
|
msg.Foo = proto.String("hello") // set field
|
||||||
|
- Constants are defined to hold the default values of all fields that
|
||||||
|
have them. They have the form Default_StructName_FieldName.
|
||||||
|
Because the getter methods handle defaulted values,
|
||||||
|
direct use of these constants should be rare.
|
||||||
|
- Enums are given type names and maps from names to values.
|
||||||
|
Enum values are prefixed by the enclosing message's name, or by the
|
||||||
|
enum's type name if it is a top-level enum. Enum types have a String
|
||||||
|
method, and a Enum method to assist in message construction.
|
||||||
|
- Nested messages, groups and enums have type names prefixed with the name of
|
||||||
|
the surrounding message type.
|
||||||
|
- Extensions are given descriptor names that start with E_,
|
||||||
|
followed by an underscore-delimited list of the nested messages
|
||||||
|
that contain it (if any) followed by the CamelCased name of the
|
||||||
|
extension field itself. HasExtension, ClearExtension, GetExtension
|
||||||
|
and SetExtension are functions for manipulating extensions.
|
||||||
|
- Oneof field sets are given a single field in their message,
|
||||||
|
with distinguished wrapper types for each possible field value.
|
||||||
|
- Marshal and Unmarshal are functions to encode and decode the wire format.
|
||||||
|
|
||||||
|
When the .proto file specifies `syntax="proto3"`, there are some differences:
|
||||||
|
|
||||||
|
- Non-repeated fields of non-message type are values instead of pointers.
|
||||||
|
- Enum types do not get an Enum method.
|
||||||
|
|
||||||
|
The simplest way to describe this is to see an example.
|
||||||
|
Given file test.proto, containing
|
||||||
|
|
||||||
|
package example;
|
||||||
|
|
||||||
|
enum FOO { X = 17; }
|
||||||
|
|
||||||
|
message Test {
|
||||||
|
required string label = 1;
|
||||||
|
optional int32 type = 2 [default=77];
|
||||||
|
repeated int64 reps = 3;
|
||||||
|
optional group OptionalGroup = 4 {
|
||||||
|
required string RequiredField = 5;
|
||||||
|
}
|
||||||
|
oneof union {
|
||||||
|
int32 number = 6;
|
||||||
|
string name = 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
The resulting file, test.pb.go, is:
|
||||||
|
|
||||||
|
package example
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
type FOO int32
|
||||||
|
const (
|
||||||
|
FOO_X FOO = 17
|
||||||
|
)
|
||||||
|
var FOO_name = map[int32]string{
|
||||||
|
17: "X",
|
||||||
|
}
|
||||||
|
var FOO_value = map[string]int32{
|
||||||
|
"X": 17,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x FOO) Enum() *FOO {
|
||||||
|
p := new(FOO)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
func (x FOO) String() string {
|
||||||
|
return proto.EnumName(FOO_name, int32(x))
|
||||||
|
}
|
||||||
|
func (x *FOO) UnmarshalJSON(data []byte) error {
|
||||||
|
value, err := proto.UnmarshalJSONEnum(FOO_value, data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*x = FOO(value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Test struct {
|
||||||
|
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
|
||||||
|
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
|
||||||
|
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
|
||||||
|
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
|
||||||
|
// Types that are valid to be assigned to Union:
|
||||||
|
// *Test_Number
|
||||||
|
// *Test_Name
|
||||||
|
Union isTest_Union `protobuf_oneof:"union"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
func (m *Test) Reset() { *m = Test{} }
|
||||||
|
func (m *Test) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Test) ProtoMessage() {}
|
||||||
|
|
||||||
|
type isTest_Union interface {
|
||||||
|
isTest_Union()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Test_Number struct {
|
||||||
|
Number int32 `protobuf:"varint,6,opt,name=number"`
|
||||||
|
}
|
||||||
|
type Test_Name struct {
|
||||||
|
Name string `protobuf:"bytes,7,opt,name=name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Test_Number) isTest_Union() {}
|
||||||
|
func (*Test_Name) isTest_Union() {}
|
||||||
|
|
||||||
|
func (m *Test) GetUnion() isTest_Union {
|
||||||
|
if m != nil {
|
||||||
|
return m.Union
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
const Default_Test_Type int32 = 77
|
||||||
|
|
||||||
|
func (m *Test) GetLabel() string {
|
||||||
|
if m != nil && m.Label != nil {
|
||||||
|
return *m.Label
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Test) GetType() int32 {
|
||||||
|
if m != nil && m.Type != nil {
|
||||||
|
return *m.Type
|
||||||
|
}
|
||||||
|
return Default_Test_Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Test) GetOptionalgroup() *Test_OptionalGroup {
|
||||||
|
if m != nil {
|
||||||
|
return m.Optionalgroup
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Test_OptionalGroup struct {
|
||||||
|
RequiredField *string `protobuf:"bytes,5,req" json:"RequiredField,omitempty"`
|
||||||
|
}
|
||||||
|
func (m *Test_OptionalGroup) Reset() { *m = Test_OptionalGroup{} }
|
||||||
|
func (m *Test_OptionalGroup) String() string { return proto.CompactTextString(m) }
|
||||||
|
|
||||||
|
func (m *Test_OptionalGroup) GetRequiredField() string {
|
||||||
|
if m != nil && m.RequiredField != nil {
|
||||||
|
return *m.RequiredField
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Test) GetNumber() int32 {
|
||||||
|
if x, ok := m.GetUnion().(*Test_Number); ok {
|
||||||
|
return x.Number
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Test) GetName() string {
|
||||||
|
if x, ok := m.GetUnion().(*Test_Name); ok {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
|
||||||
|
}
|
||||||
|
|
||||||
|
To create and play with a Test object:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
pb "./example.pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
test := &pb.Test{
|
||||||
|
Label: proto.String("hello"),
|
||||||
|
Type: proto.Int32(17),
|
||||||
|
Reps: []int64{1, 2, 3},
|
||||||
|
Optionalgroup: &pb.Test_OptionalGroup{
|
||||||
|
RequiredField: proto.String("good bye"),
|
||||||
|
},
|
||||||
|
Union: &pb.Test_Name{"fred"},
|
||||||
|
}
|
||||||
|
data, err := proto.Marshal(test)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("marshaling error: ", err)
|
||||||
|
}
|
||||||
|
newTest := &pb.Test{}
|
||||||
|
err = proto.Unmarshal(data, newTest)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("unmarshaling error: ", err)
|
||||||
|
}
|
||||||
|
// Now test and newTest contain the same data.
|
||||||
|
if test.GetLabel() != newTest.GetLabel() {
|
||||||
|
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
|
||||||
|
}
|
||||||
|
// Use a type switch to determine which oneof was set.
|
||||||
|
switch u := test.Union.(type) {
|
||||||
|
case *pb.Test_Number: // u.Number contains the number.
|
||||||
|
case *pb.Test_Name: // u.Name contains the string.
|
||||||
|
}
|
||||||
|
// etc.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Message is implemented by generated protocol buffer messages.
|
||||||
|
type Message interface {
|
||||||
|
Reset()
|
||||||
|
String() string
|
||||||
|
ProtoMessage()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats records allocation details about the protocol buffer encoders
|
||||||
|
// and decoders. Useful for tuning the library itself.
|
||||||
|
type Stats struct {
|
||||||
|
Emalloc uint64 // mallocs in encode
|
||||||
|
Dmalloc uint64 // mallocs in decode
|
||||||
|
Encode uint64 // number of encodes
|
||||||
|
Decode uint64 // number of decodes
|
||||||
|
Chit uint64 // number of cache hits
|
||||||
|
Cmiss uint64 // number of cache misses
|
||||||
|
Size uint64 // number of sizes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set to true to enable stats collection.
|
||||||
|
const collectStats = false
|
||||||
|
|
||||||
|
var stats Stats
|
||||||
|
|
||||||
|
// GetStats returns a copy of the global Stats structure.
|
||||||
|
func GetStats() Stats { return stats }
|
||||||
|
|
||||||
|
// A Buffer is a buffer manager for marshaling and unmarshaling
|
||||||
|
// protocol buffers. It may be reused between invocations to
|
||||||
|
// reduce memory usage. It is not necessary to use a Buffer;
|
||||||
|
// the global functions Marshal and Unmarshal create a
|
||||||
|
// temporary Buffer and are fine for most applications.
|
||||||
|
type Buffer struct {
|
||||||
|
buf []byte // encode/decode byte stream
|
||||||
|
index int // read point
|
||||||
|
|
||||||
|
// pools of basic types to amortize allocation.
|
||||||
|
bools []bool
|
||||||
|
uint32s []uint32
|
||||||
|
uint64s []uint64
|
||||||
|
|
||||||
|
// extra pools, only used with pointer_reflect.go
|
||||||
|
int32s []int32
|
||||||
|
int64s []int64
|
||||||
|
float32s []float32
|
||||||
|
float64s []float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuffer allocates a new Buffer and initializes its internal data to
|
||||||
|
// the contents of the argument slice.
|
||||||
|
func NewBuffer(e []byte) *Buffer {
|
||||||
|
return &Buffer{buf: e}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset resets the Buffer, ready for marshaling a new protocol buffer.
|
||||||
|
func (p *Buffer) Reset() {
|
||||||
|
p.buf = p.buf[0:0] // for reading/writing
|
||||||
|
p.index = 0 // for reading
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBuf replaces the internal buffer with the slice,
|
||||||
|
// ready for unmarshaling the contents of the slice.
|
||||||
|
func (p *Buffer) SetBuf(s []byte) {
|
||||||
|
p.buf = s
|
||||||
|
p.index = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the contents of the Buffer.
|
||||||
|
func (p *Buffer) Bytes() []byte { return p.buf }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper routines for simplifying the creation of optional fields of basic type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Bool is a helper routine that allocates a new bool value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Bool(v bool) *bool {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32 is a helper routine that allocates a new int32 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Int32(v int32) *int32 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int is a helper routine that allocates a new int32 value
|
||||||
|
// to store v and returns a pointer to it, but unlike Int32
|
||||||
|
// its argument value is an int.
|
||||||
|
func Int(v int) *int32 {
|
||||||
|
p := new(int32)
|
||||||
|
*p = int32(v)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 is a helper routine that allocates a new int64 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Int64(v int64) *int64 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32 is a helper routine that allocates a new float32 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Float32(v float32) *float32 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 is a helper routine that allocates a new float64 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Float64(v float64) *float64 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint32 is a helper routine that allocates a new uint32 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Uint32(v uint32) *uint32 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64 is a helper routine that allocates a new uint64 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Uint64(v uint64) *uint64 {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is a helper routine that allocates a new string value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func String(v string) *string {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnumName is a helper function to simplify printing protocol buffer enums
|
||||||
|
// by name. Given an enum map and a value, it returns a useful string.
|
||||||
|
func EnumName(m map[int32]string, v int32) string {
|
||||||
|
s, ok := m[v]
|
||||||
|
if ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return strconv.Itoa(int(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSONEnum is a helper function to simplify recovering enum int values
|
||||||
|
// from their JSON-encoded representation. Given a map from the enum's symbolic
|
||||||
|
// names to its int values, and a byte buffer containing the JSON-encoded
|
||||||
|
// value, it returns an int32 that can be cast to the enum type by the caller.
|
||||||
|
//
|
||||||
|
// The function can deal with both JSON representations, numeric and symbolic.
|
||||||
|
func UnmarshalJSONEnum(m map[string]int32, data []byte, enumName string) (int32, error) {
|
||||||
|
if data[0] == '"' {
|
||||||
|
// New style: enums are strings.
|
||||||
|
var repr string
|
||||||
|
if err := json.Unmarshal(data, &repr); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
val, ok := m[repr]
|
||||||
|
if !ok {
|
||||||
|
return 0, fmt.Errorf("unrecognized enum %s value %q", enumName, repr)
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
// Old style: enums are ints.
|
||||||
|
var val int32
|
||||||
|
if err := json.Unmarshal(data, &val); err != nil {
|
||||||
|
return 0, fmt.Errorf("cannot unmarshal %#q into enum %s", data, enumName)
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebugPrint dumps the encoded data in b in a debugging format with a header
|
||||||
|
// including the string s. Used in testing but made available for general debugging.
|
||||||
|
func (p *Buffer) DebugPrint(s string, b []byte) {
|
||||||
|
var u uint64
|
||||||
|
|
||||||
|
obuf := p.buf
|
||||||
|
index := p.index
|
||||||
|
p.buf = b
|
||||||
|
p.index = 0
|
||||||
|
depth := 0
|
||||||
|
|
||||||
|
fmt.Printf("\n--- %s ---\n", s)
|
||||||
|
|
||||||
|
out:
|
||||||
|
for {
|
||||||
|
for i := 0; i < depth; i++ {
|
||||||
|
fmt.Print(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
index := p.index
|
||||||
|
if index == len(p.buf) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
op, err := p.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%3d: fetching op err %v\n", index, err)
|
||||||
|
break out
|
||||||
|
}
|
||||||
|
tag := op >> 3
|
||||||
|
wire := op & 7
|
||||||
|
|
||||||
|
switch wire {
|
||||||
|
default:
|
||||||
|
fmt.Printf("%3d: t=%3d unknown wire=%d\n",
|
||||||
|
index, tag, wire)
|
||||||
|
break out
|
||||||
|
|
||||||
|
case WireBytes:
|
||||||
|
var r []byte
|
||||||
|
|
||||||
|
r, err = p.DecodeRawBytes(false)
|
||||||
|
if err != nil {
|
||||||
|
break out
|
||||||
|
}
|
||||||
|
fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r))
|
||||||
|
if len(r) <= 6 {
|
||||||
|
for i := 0; i < len(r); i++ {
|
||||||
|
fmt.Printf(" %.2x", r[i])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
fmt.Printf(" %.2x", r[i])
|
||||||
|
}
|
||||||
|
fmt.Printf(" ..")
|
||||||
|
for i := len(r) - 3; i < len(r); i++ {
|
||||||
|
fmt.Printf(" %.2x", r[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
|
||||||
|
case WireFixed32:
|
||||||
|
u, err = p.DecodeFixed32()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err)
|
||||||
|
break out
|
||||||
|
}
|
||||||
|
fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u)
|
||||||
|
|
||||||
|
case WireFixed64:
|
||||||
|
u, err = p.DecodeFixed64()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err)
|
||||||
|
break out
|
||||||
|
}
|
||||||
|
fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
|
||||||
|
|
||||||
|
case WireVarint:
|
||||||
|
u, err = p.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err)
|
||||||
|
break out
|
||||||
|
}
|
||||||
|
fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
|
||||||
|
|
||||||
|
case WireStartGroup:
|
||||||
|
fmt.Printf("%3d: t=%3d start\n", index, tag)
|
||||||
|
depth++
|
||||||
|
|
||||||
|
case WireEndGroup:
|
||||||
|
depth--
|
||||||
|
fmt.Printf("%3d: t=%3d end\n", index, tag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if depth != 0 {
|
||||||
|
fmt.Printf("%3d: start-end not balanced %d\n", p.index, depth)
|
||||||
|
}
|
||||||
|
fmt.Printf("\n")
|
||||||
|
|
||||||
|
p.buf = obuf
|
||||||
|
p.index = index
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDefaults sets unset protocol buffer fields to their default values.
|
||||||
|
// It only modifies fields that are both unset and have defined defaults.
|
||||||
|
// It recursively sets default values in any non-nil sub-messages.
|
||||||
|
func SetDefaults(pb Message) {
|
||||||
|
setDefaults(reflect.ValueOf(pb), true, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// v is a pointer to a struct.
|
||||||
|
func setDefaults(v reflect.Value, recur, zeros bool) {
|
||||||
|
v = v.Elem()
|
||||||
|
|
||||||
|
defaultMu.RLock()
|
||||||
|
dm, ok := defaults[v.Type()]
|
||||||
|
defaultMu.RUnlock()
|
||||||
|
if !ok {
|
||||||
|
dm = buildDefaultMessage(v.Type())
|
||||||
|
defaultMu.Lock()
|
||||||
|
defaults[v.Type()] = dm
|
||||||
|
defaultMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sf := range dm.scalars {
|
||||||
|
f := v.Field(sf.index)
|
||||||
|
if !f.IsNil() {
|
||||||
|
// field already set
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dv := sf.value
|
||||||
|
if dv == nil && !zeros {
|
||||||
|
// no explicit default, and don't want to set zeros
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fptr := f.Addr().Interface() // **T
|
||||||
|
// TODO: Consider batching the allocations we do here.
|
||||||
|
switch sf.kind {
|
||||||
|
case reflect.Bool:
|
||||||
|
b := new(bool)
|
||||||
|
if dv != nil {
|
||||||
|
*b = dv.(bool)
|
||||||
|
}
|
||||||
|
*(fptr.(**bool)) = b
|
||||||
|
case reflect.Float32:
|
||||||
|
f := new(float32)
|
||||||
|
if dv != nil {
|
||||||
|
*f = dv.(float32)
|
||||||
|
}
|
||||||
|
*(fptr.(**float32)) = f
|
||||||
|
case reflect.Float64:
|
||||||
|
f := new(float64)
|
||||||
|
if dv != nil {
|
||||||
|
*f = dv.(float64)
|
||||||
|
}
|
||||||
|
*(fptr.(**float64)) = f
|
||||||
|
case reflect.Int32:
|
||||||
|
// might be an enum
|
||||||
|
if ft := f.Type(); ft != int32PtrType {
|
||||||
|
// enum
|
||||||
|
f.Set(reflect.New(ft.Elem()))
|
||||||
|
if dv != nil {
|
||||||
|
f.Elem().SetInt(int64(dv.(int32)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// int32 field
|
||||||
|
i := new(int32)
|
||||||
|
if dv != nil {
|
||||||
|
*i = dv.(int32)
|
||||||
|
}
|
||||||
|
*(fptr.(**int32)) = i
|
||||||
|
}
|
||||||
|
case reflect.Int64:
|
||||||
|
i := new(int64)
|
||||||
|
if dv != nil {
|
||||||
|
*i = dv.(int64)
|
||||||
|
}
|
||||||
|
*(fptr.(**int64)) = i
|
||||||
|
case reflect.String:
|
||||||
|
s := new(string)
|
||||||
|
if dv != nil {
|
||||||
|
*s = dv.(string)
|
||||||
|
}
|
||||||
|
*(fptr.(**string)) = s
|
||||||
|
case reflect.Uint8:
|
||||||
|
// exceptional case: []byte
|
||||||
|
var b []byte
|
||||||
|
if dv != nil {
|
||||||
|
db := dv.([]byte)
|
||||||
|
b = make([]byte, len(db))
|
||||||
|
copy(b, db)
|
||||||
|
} else {
|
||||||
|
b = []byte{}
|
||||||
|
}
|
||||||
|
*(fptr.(*[]byte)) = b
|
||||||
|
case reflect.Uint32:
|
||||||
|
u := new(uint32)
|
||||||
|
if dv != nil {
|
||||||
|
*u = dv.(uint32)
|
||||||
|
}
|
||||||
|
*(fptr.(**uint32)) = u
|
||||||
|
case reflect.Uint64:
|
||||||
|
u := new(uint64)
|
||||||
|
if dv != nil {
|
||||||
|
*u = dv.(uint64)
|
||||||
|
}
|
||||||
|
*(fptr.(**uint64)) = u
|
||||||
|
default:
|
||||||
|
log.Printf("proto: can't set default for field %v (sf.kind=%v)", f, sf.kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ni := range dm.nested {
|
||||||
|
f := v.Field(ni)
|
||||||
|
// f is *T or []*T or map[T]*T
|
||||||
|
switch f.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
if f.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
setDefaults(f, recur, zeros)
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
for i := 0; i < f.Len(); i++ {
|
||||||
|
e := f.Index(i)
|
||||||
|
if e.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
setDefaults(e, recur, zeros)
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
for _, k := range f.MapKeys() {
|
||||||
|
e := f.MapIndex(k)
|
||||||
|
if e.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
setDefaults(e, recur, zeros)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// defaults maps a protocol buffer struct type to a slice of the fields,
|
||||||
|
// with its scalar fields set to their proto-declared non-zero default values.
|
||||||
|
defaultMu sync.RWMutex
|
||||||
|
defaults = make(map[reflect.Type]defaultMessage)
|
||||||
|
|
||||||
|
int32PtrType = reflect.TypeOf((*int32)(nil))
|
||||||
|
)
|
||||||
|
|
||||||
|
// defaultMessage represents information about the default values of a message.
|
||||||
|
type defaultMessage struct {
|
||||||
|
scalars []scalarField
|
||||||
|
nested []int // struct field index of nested messages
|
||||||
|
}
|
||||||
|
|
||||||
|
type scalarField struct {
|
||||||
|
index int // struct field index
|
||||||
|
kind reflect.Kind // element type (the T in *T or []T)
|
||||||
|
value interface{} // the proto-declared default value, or nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// t is a struct type.
|
||||||
|
func buildDefaultMessage(t reflect.Type) (dm defaultMessage) {
|
||||||
|
sprop := GetProperties(t)
|
||||||
|
for _, prop := range sprop.Prop {
|
||||||
|
fi, ok := sprop.decoderTags.get(prop.Tag)
|
||||||
|
if !ok {
|
||||||
|
// XXX_unrecognized
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ft := t.Field(fi).Type
|
||||||
|
|
||||||
|
sf, nested, err := fieldDefault(ft, prop)
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
log.Print(err)
|
||||||
|
case nested:
|
||||||
|
dm.nested = append(dm.nested, fi)
|
||||||
|
case sf != nil:
|
||||||
|
sf.index = fi
|
||||||
|
dm.scalars = append(dm.scalars, *sf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dm
|
||||||
|
}
|
||||||
|
|
||||||
|
// fieldDefault returns the scalarField for field type ft.
|
||||||
|
// sf will be nil if the field can not have a default.
|
||||||
|
// nestedMessage will be true if this is a nested message.
|
||||||
|
// Note that sf.index is not set on return.
|
||||||
|
func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMessage bool, err error) {
|
||||||
|
var canHaveDefault bool
|
||||||
|
switch ft.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
if ft.Elem().Kind() == reflect.Struct {
|
||||||
|
nestedMessage = true
|
||||||
|
} else {
|
||||||
|
canHaveDefault = true // proto2 scalar field
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
switch ft.Elem().Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
nestedMessage = true // repeated message
|
||||||
|
case reflect.Uint8:
|
||||||
|
canHaveDefault = true // bytes field
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
if ft.Elem().Kind() == reflect.Ptr {
|
||||||
|
nestedMessage = true // map with message values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !canHaveDefault {
|
||||||
|
if nestedMessage {
|
||||||
|
return nil, true, nil
|
||||||
|
}
|
||||||
|
return nil, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now know that ft is a pointer or slice.
|
||||||
|
sf = &scalarField{kind: ft.Elem().Kind()}
|
||||||
|
|
||||||
|
// scalar fields without defaults
|
||||||
|
if !prop.HasDefault {
|
||||||
|
return sf, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// a scalar field: either *T or []byte
|
||||||
|
switch ft.Elem().Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
x, err := strconv.ParseBool(prop.Default)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("proto: bad default bool %q: %v", prop.Default, err)
|
||||||
|
}
|
||||||
|
sf.value = x
|
||||||
|
case reflect.Float32:
|
||||||
|
x, err := strconv.ParseFloat(prop.Default, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("proto: bad default float32 %q: %v", prop.Default, err)
|
||||||
|
}
|
||||||
|
sf.value = float32(x)
|
||||||
|
case reflect.Float64:
|
||||||
|
x, err := strconv.ParseFloat(prop.Default, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("proto: bad default float64 %q: %v", prop.Default, err)
|
||||||
|
}
|
||||||
|
sf.value = x
|
||||||
|
case reflect.Int32:
|
||||||
|
x, err := strconv.ParseInt(prop.Default, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("proto: bad default int32 %q: %v", prop.Default, err)
|
||||||
|
}
|
||||||
|
sf.value = int32(x)
|
||||||
|
case reflect.Int64:
|
||||||
|
x, err := strconv.ParseInt(prop.Default, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("proto: bad default int64 %q: %v", prop.Default, err)
|
||||||
|
}
|
||||||
|
sf.value = x
|
||||||
|
case reflect.String:
|
||||||
|
sf.value = prop.Default
|
||||||
|
case reflect.Uint8:
|
||||||
|
// []byte (not *uint8)
|
||||||
|
sf.value = []byte(prop.Default)
|
||||||
|
case reflect.Uint32:
|
||||||
|
x, err := strconv.ParseUint(prop.Default, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("proto: bad default uint32 %q: %v", prop.Default, err)
|
||||||
|
}
|
||||||
|
sf.value = uint32(x)
|
||||||
|
case reflect.Uint64:
|
||||||
|
x, err := strconv.ParseUint(prop.Default, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, fmt.Errorf("proto: bad default uint64 %q: %v", prop.Default, err)
|
||||||
|
}
|
||||||
|
sf.value = x
|
||||||
|
default:
|
||||||
|
return nil, false, fmt.Errorf("proto: unhandled def kind %v", ft.Elem().Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
return sf, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map fields may have key types of non-float scalars, strings and enums.
|
||||||
|
// The easiest way to sort them in some deterministic order is to use fmt.
|
||||||
|
// If this turns out to be inefficient we can always consider other options,
|
||||||
|
// such as doing a Schwartzian transform.
|
||||||
|
|
||||||
|
func mapKeys(vs []reflect.Value) sort.Interface {
|
||||||
|
s := mapKeySorter{
|
||||||
|
vs: vs,
|
||||||
|
// default Less function: textual comparison
|
||||||
|
less: func(a, b reflect.Value) bool {
|
||||||
|
return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps;
|
||||||
|
// numeric keys are sorted numerically.
|
||||||
|
if len(vs) == 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
switch vs[0].Kind() {
|
||||||
|
case reflect.Int32, reflect.Int64:
|
||||||
|
s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
|
||||||
|
case reflect.Uint32, reflect.Uint64:
|
||||||
|
s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapKeySorter struct {
|
||||||
|
vs []reflect.Value
|
||||||
|
less func(a, b reflect.Value) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s mapKeySorter) Len() int { return len(s.vs) }
|
||||||
|
func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] }
|
||||||
|
func (s mapKeySorter) Less(i, j int) bool {
|
||||||
|
return s.less(s.vs[i], s.vs[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
// isProto3Zero reports whether v is a zero proto3 value.
|
||||||
|
func isProto3Zero(v reflect.Value) bool {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return !v.Bool()
|
||||||
|
case reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int() == 0
|
||||||
|
case reflect.Uint32, reflect.Uint64:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float() == 0
|
||||||
|
case reflect.String:
|
||||||
|
return v.String() == ""
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProtoPackageIsVersion2 is referenced from generated protocol buffer files
|
||||||
|
// to assert that that code is compatible with this version of the proto package.
|
||||||
|
const ProtoPackageIsVersion2 = true
|
||||||
|
|
||||||
|
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
|
||||||
|
// to assert that that code is compatible with this version of the proto package.
|
||||||
|
const ProtoPackageIsVersion1 = true
|
311
vendor/github.com/golang/protobuf/proto/message_set.go
generated
vendored
Normal file
311
vendor/github.com/golang/protobuf/proto/message_set.go
generated
vendored
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support for message sets.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
|
||||||
|
// A message type ID is required for storing a protocol buffer in a message set.
|
||||||
|
var errNoMessageTypeID = errors.New("proto does not have a message type ID")
|
||||||
|
|
||||||
|
// The first two types (_MessageSet_Item and messageSet)
|
||||||
|
// model what the protocol compiler produces for the following protocol message:
|
||||||
|
// message MessageSet {
|
||||||
|
// repeated group Item = 1 {
|
||||||
|
// required int32 type_id = 2;
|
||||||
|
// required string message = 3;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// That is the MessageSet wire format. We can't use a proto to generate these
|
||||||
|
// because that would introduce a circular dependency between it and this package.
|
||||||
|
|
||||||
|
type _MessageSet_Item struct {
|
||||||
|
TypeId *int32 `protobuf:"varint,2,req,name=type_id"`
|
||||||
|
Message []byte `protobuf:"bytes,3,req,name=message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type messageSet struct {
|
||||||
|
Item []*_MessageSet_Item `protobuf:"group,1,rep"`
|
||||||
|
XXX_unrecognized []byte
|
||||||
|
// TODO: caching?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure messageSet is a Message.
|
||||||
|
var _ Message = (*messageSet)(nil)
|
||||||
|
|
||||||
|
// messageTypeIder is an interface satisfied by a protocol buffer type
|
||||||
|
// that may be stored in a MessageSet.
|
||||||
|
type messageTypeIder interface {
|
||||||
|
MessageTypeId() int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *messageSet) find(pb Message) *_MessageSet_Item {
|
||||||
|
mti, ok := pb.(messageTypeIder)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
id := mti.MessageTypeId()
|
||||||
|
for _, item := range ms.Item {
|
||||||
|
if *item.TypeId == id {
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *messageSet) Has(pb Message) bool {
|
||||||
|
if ms.find(pb) != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *messageSet) Unmarshal(pb Message) error {
|
||||||
|
if item := ms.find(pb); item != nil {
|
||||||
|
return Unmarshal(item.Message, pb)
|
||||||
|
}
|
||||||
|
if _, ok := pb.(messageTypeIder); !ok {
|
||||||
|
return errNoMessageTypeID
|
||||||
|
}
|
||||||
|
return nil // TODO: return error instead?
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *messageSet) Marshal(pb Message) error {
|
||||||
|
msg, err := Marshal(pb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if item := ms.find(pb); item != nil {
|
||||||
|
// reuse existing item
|
||||||
|
item.Message = msg
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mti, ok := pb.(messageTypeIder)
|
||||||
|
if !ok {
|
||||||
|
return errNoMessageTypeID
|
||||||
|
}
|
||||||
|
|
||||||
|
mtid := mti.MessageTypeId()
|
||||||
|
ms.Item = append(ms.Item, &_MessageSet_Item{
|
||||||
|
TypeId: &mtid,
|
||||||
|
Message: msg,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *messageSet) Reset() { *ms = messageSet{} }
|
||||||
|
func (ms *messageSet) String() string { return CompactTextString(ms) }
|
||||||
|
func (*messageSet) ProtoMessage() {}
|
||||||
|
|
||||||
|
// Support for the message_set_wire_format message option.
|
||||||
|
|
||||||
|
func skipVarint(buf []byte) []byte {
|
||||||
|
i := 0
|
||||||
|
for ; buf[i]&0x80 != 0; i++ {
|
||||||
|
}
|
||||||
|
return buf[i+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
|
||||||
|
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
|
func MarshalMessageSet(exts interface{}) ([]byte, error) {
|
||||||
|
var m map[int32]Extension
|
||||||
|
switch exts := exts.(type) {
|
||||||
|
case *XXX_InternalExtensions:
|
||||||
|
if err := encodeExtensions(exts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m, _ = exts.extensionsRead()
|
||||||
|
case map[int32]Extension:
|
||||||
|
if err := encodeExtensionsMap(exts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
m = exts
|
||||||
|
default:
|
||||||
|
return nil, errors.New("proto: not an extension map")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort extension IDs to provide a deterministic encoding.
|
||||||
|
// See also enc_map in encode.go.
|
||||||
|
ids := make([]int, 0, len(m))
|
||||||
|
for id := range m {
|
||||||
|
ids = append(ids, int(id))
|
||||||
|
}
|
||||||
|
sort.Ints(ids)
|
||||||
|
|
||||||
|
ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
|
||||||
|
for _, id := range ids {
|
||||||
|
e := m[int32(id)]
|
||||||
|
// Remove the wire type and field number varint, as well as the length varint.
|
||||||
|
msg := skipVarint(skipVarint(e.enc))
|
||||||
|
|
||||||
|
ms.Item = append(ms.Item, &_MessageSet_Item{
|
||||||
|
TypeId: Int32(int32(id)),
|
||||||
|
Message: msg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return Marshal(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
||||||
|
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
|
func UnmarshalMessageSet(buf []byte, exts interface{}) error {
|
||||||
|
var m map[int32]Extension
|
||||||
|
switch exts := exts.(type) {
|
||||||
|
case *XXX_InternalExtensions:
|
||||||
|
m = exts.extensionsWrite()
|
||||||
|
case map[int32]Extension:
|
||||||
|
m = exts
|
||||||
|
default:
|
||||||
|
return errors.New("proto: not an extension map")
|
||||||
|
}
|
||||||
|
|
||||||
|
ms := new(messageSet)
|
||||||
|
if err := Unmarshal(buf, ms); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, item := range ms.Item {
|
||||||
|
id := *item.TypeId
|
||||||
|
msg := item.Message
|
||||||
|
|
||||||
|
// Restore wire type and field number varint, plus length varint.
|
||||||
|
// Be careful to preserve duplicate items.
|
||||||
|
b := EncodeVarint(uint64(id)<<3 | WireBytes)
|
||||||
|
if ext, ok := m[id]; ok {
|
||||||
|
// Existing data; rip off the tag and length varint
|
||||||
|
// so we join the new data correctly.
|
||||||
|
// We can assume that ext.enc is set because we are unmarshaling.
|
||||||
|
o := ext.enc[len(b):] // skip wire type and field number
|
||||||
|
_, n := DecodeVarint(o) // calculate length of length varint
|
||||||
|
o = o[n:] // skip length varint
|
||||||
|
msg = append(o, msg...) // join old data and new data
|
||||||
|
}
|
||||||
|
b = append(b, EncodeVarint(uint64(len(msg)))...)
|
||||||
|
b = append(b, msg...)
|
||||||
|
|
||||||
|
m[id] = Extension{enc: b}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
|
||||||
|
// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
|
func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
|
||||||
|
var m map[int32]Extension
|
||||||
|
switch exts := exts.(type) {
|
||||||
|
case *XXX_InternalExtensions:
|
||||||
|
m, _ = exts.extensionsRead()
|
||||||
|
case map[int32]Extension:
|
||||||
|
m = exts
|
||||||
|
default:
|
||||||
|
return nil, errors.New("proto: not an extension map")
|
||||||
|
}
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteByte('{')
|
||||||
|
|
||||||
|
// Process the map in key order for deterministic output.
|
||||||
|
ids := make([]int32, 0, len(m))
|
||||||
|
for id := range m {
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
|
||||||
|
|
||||||
|
for i, id := range ids {
|
||||||
|
ext := m[id]
|
||||||
|
if i > 0 {
|
||||||
|
b.WriteByte(',')
|
||||||
|
}
|
||||||
|
|
||||||
|
msd, ok := messageSetMap[id]
|
||||||
|
if !ok {
|
||||||
|
// Unknown type; we can't render it, so skip it.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&b, `"[%s]":`, msd.name)
|
||||||
|
|
||||||
|
x := ext.value
|
||||||
|
if x == nil {
|
||||||
|
x = reflect.New(msd.t.Elem()).Interface()
|
||||||
|
if err := Unmarshal(ext.enc, x.(Message)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d, err := json.Marshal(x)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b.Write(d)
|
||||||
|
}
|
||||||
|
b.WriteByte('}')
|
||||||
|
return b.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
|
||||||
|
// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
|
func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error {
|
||||||
|
// Common-case fast path.
|
||||||
|
if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is fairly tricky, and it's not clear that it is needed.
|
||||||
|
return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// A global registry of types that can be used in a MessageSet.
|
||||||
|
|
||||||
|
var messageSetMap = make(map[int32]messageSetDesc)
|
||||||
|
|
||||||
|
type messageSetDesc struct {
|
||||||
|
t reflect.Type // pointer to struct
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterMessageSetType is called from the generated code.
|
||||||
|
func RegisterMessageSetType(m Message, fieldNum int32, name string) {
|
||||||
|
messageSetMap[fieldNum] = messageSetDesc{
|
||||||
|
t: reflect.TypeOf(m),
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
|
}
|
484
vendor/github.com/golang/protobuf/proto/pointer_reflect.go
generated
vendored
Normal file
484
vendor/github.com/golang/protobuf/proto/pointer_reflect.go
generated
vendored
Normal file
|
@ -0,0 +1,484 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
// +build appengine js
|
||||||
|
|
||||||
|
// This file contains an implementation of proto field accesses using package reflect.
|
||||||
|
// It is slower than the code in pointer_unsafe.go but it avoids package unsafe and can
|
||||||
|
// be used on App Engine.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A structPointer is a pointer to a struct.
|
||||||
|
type structPointer struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// toStructPointer returns a structPointer equivalent to the given reflect value.
|
||||||
|
// The reflect value must itself be a pointer to a struct.
|
||||||
|
func toStructPointer(v reflect.Value) structPointer {
|
||||||
|
return structPointer{v}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNil reports whether p is nil.
|
||||||
|
func structPointer_IsNil(p structPointer) bool {
|
||||||
|
return p.v.IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface returns the struct pointer as an interface value.
|
||||||
|
func structPointer_Interface(p structPointer, _ reflect.Type) interface{} {
|
||||||
|
return p.v.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A field identifies a field in a struct, accessible from a structPointer.
|
||||||
|
// In this implementation, a field is identified by the sequence of field indices
|
||||||
|
// passed to reflect's FieldByIndex.
|
||||||
|
type field []int
|
||||||
|
|
||||||
|
// toField returns a field equivalent to the given reflect field.
|
||||||
|
func toField(f *reflect.StructField) field {
|
||||||
|
return f.Index
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidField is an invalid field identifier.
|
||||||
|
var invalidField = field(nil)
|
||||||
|
|
||||||
|
// IsValid reports whether the field identifier is valid.
|
||||||
|
func (f field) IsValid() bool { return f != nil }
|
||||||
|
|
||||||
|
// field returns the given field in the struct as a reflect value.
|
||||||
|
func structPointer_field(p structPointer, f field) reflect.Value {
|
||||||
|
// Special case: an extension map entry with a value of type T
|
||||||
|
// passes a *T to the struct-handling code with a zero field,
|
||||||
|
// expecting that it will be treated as equivalent to *struct{ X T },
|
||||||
|
// which has the same memory layout. We have to handle that case
|
||||||
|
// specially, because reflect will panic if we call FieldByIndex on a
|
||||||
|
// non-struct.
|
||||||
|
if f == nil {
|
||||||
|
return p.v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.v.Elem().FieldByIndex(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ifield returns the given field in the struct as an interface value.
|
||||||
|
func structPointer_ifield(p structPointer, f field) interface{} {
|
||||||
|
return structPointer_field(p, f).Addr().Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the address of a []byte field in the struct.
|
||||||
|
func structPointer_Bytes(p structPointer, f field) *[]byte {
|
||||||
|
return structPointer_ifield(p, f).(*[]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesSlice returns the address of a [][]byte field in the struct.
|
||||||
|
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
|
||||||
|
return structPointer_ifield(p, f).(*[][]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns the address of a *bool field in the struct.
|
||||||
|
func structPointer_Bool(p structPointer, f field) **bool {
|
||||||
|
return structPointer_ifield(p, f).(**bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolVal returns the address of a bool field in the struct.
|
||||||
|
func structPointer_BoolVal(p structPointer, f field) *bool {
|
||||||
|
return structPointer_ifield(p, f).(*bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSlice returns the address of a []bool field in the struct.
|
||||||
|
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
|
||||||
|
return structPointer_ifield(p, f).(*[]bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the address of a *string field in the struct.
|
||||||
|
func structPointer_String(p structPointer, f field) **string {
|
||||||
|
return structPointer_ifield(p, f).(**string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringVal returns the address of a string field in the struct.
|
||||||
|
func structPointer_StringVal(p structPointer, f field) *string {
|
||||||
|
return structPointer_ifield(p, f).(*string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice returns the address of a []string field in the struct.
|
||||||
|
func structPointer_StringSlice(p structPointer, f field) *[]string {
|
||||||
|
return structPointer_ifield(p, f).(*[]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extensions returns the address of an extension map field in the struct.
|
||||||
|
func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
|
||||||
|
return structPointer_ifield(p, f).(*XXX_InternalExtensions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtMap returns the address of an extension map field in the struct.
|
||||||
|
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
|
||||||
|
return structPointer_ifield(p, f).(*map[int32]Extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAt returns the reflect.Value for a pointer to a field in the struct.
|
||||||
|
func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value {
|
||||||
|
return structPointer_field(p, f).Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStructPointer writes a *struct field in the struct.
|
||||||
|
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
|
||||||
|
structPointer_field(p, f).Set(q.v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStructPointer reads a *struct field in the struct.
|
||||||
|
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
|
||||||
|
return structPointer{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructPointerSlice the address of a []*struct field in the struct.
|
||||||
|
func structPointer_StructPointerSlice(p structPointer, f field) structPointerSlice {
|
||||||
|
return structPointerSlice{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A structPointerSlice represents the address of a slice of pointers to structs
|
||||||
|
// (themselves messages or groups). That is, v.Type() is *[]*struct{...}.
|
||||||
|
type structPointerSlice struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p structPointerSlice) Len() int { return p.v.Len() }
|
||||||
|
func (p structPointerSlice) Index(i int) structPointer { return structPointer{p.v.Index(i)} }
|
||||||
|
func (p structPointerSlice) Append(q structPointer) {
|
||||||
|
p.v.Set(reflect.Append(p.v, q.v))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
int32Type = reflect.TypeOf(int32(0))
|
||||||
|
uint32Type = reflect.TypeOf(uint32(0))
|
||||||
|
float32Type = reflect.TypeOf(float32(0))
|
||||||
|
int64Type = reflect.TypeOf(int64(0))
|
||||||
|
uint64Type = reflect.TypeOf(uint64(0))
|
||||||
|
float64Type = reflect.TypeOf(float64(0))
|
||||||
|
)
|
||||||
|
|
||||||
|
// A word32 represents a field of type *int32, *uint32, *float32, or *enum.
|
||||||
|
// That is, v.Type() is *int32, *uint32, *float32, or *enum and v is assignable.
|
||||||
|
type word32 struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNil reports whether p is nil.
|
||||||
|
func word32_IsNil(p word32) bool {
|
||||||
|
return p.v.IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets p to point at a newly allocated word with bits set to x.
|
||||||
|
func word32_Set(p word32, o *Buffer, x uint32) {
|
||||||
|
t := p.v.Type().Elem()
|
||||||
|
switch t {
|
||||||
|
case int32Type:
|
||||||
|
if len(o.int32s) == 0 {
|
||||||
|
o.int32s = make([]int32, uint32PoolSize)
|
||||||
|
}
|
||||||
|
o.int32s[0] = int32(x)
|
||||||
|
p.v.Set(reflect.ValueOf(&o.int32s[0]))
|
||||||
|
o.int32s = o.int32s[1:]
|
||||||
|
return
|
||||||
|
case uint32Type:
|
||||||
|
if len(o.uint32s) == 0 {
|
||||||
|
o.uint32s = make([]uint32, uint32PoolSize)
|
||||||
|
}
|
||||||
|
o.uint32s[0] = x
|
||||||
|
p.v.Set(reflect.ValueOf(&o.uint32s[0]))
|
||||||
|
o.uint32s = o.uint32s[1:]
|
||||||
|
return
|
||||||
|
case float32Type:
|
||||||
|
if len(o.float32s) == 0 {
|
||||||
|
o.float32s = make([]float32, uint32PoolSize)
|
||||||
|
}
|
||||||
|
o.float32s[0] = math.Float32frombits(x)
|
||||||
|
p.v.Set(reflect.ValueOf(&o.float32s[0]))
|
||||||
|
o.float32s = o.float32s[1:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be enum
|
||||||
|
p.v.Set(reflect.New(t))
|
||||||
|
p.v.Elem().SetInt(int64(int32(x)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the bits pointed at by p, as a uint32.
|
||||||
|
func word32_Get(p word32) uint32 {
|
||||||
|
elem := p.v.Elem()
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int32:
|
||||||
|
return uint32(elem.Int())
|
||||||
|
case reflect.Uint32:
|
||||||
|
return uint32(elem.Uint())
|
||||||
|
case reflect.Float32:
|
||||||
|
return math.Float32bits(float32(elem.Float()))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32 returns a reference to a *int32, *uint32, *float32, or *enum field in the struct.
|
||||||
|
func structPointer_Word32(p structPointer, f field) word32 {
|
||||||
|
return word32{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A word32Val represents a field of type int32, uint32, float32, or enum.
|
||||||
|
// That is, v.Type() is int32, uint32, float32, or enum and v is assignable.
|
||||||
|
type word32Val struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets *p to x.
|
||||||
|
func word32Val_Set(p word32Val, x uint32) {
|
||||||
|
switch p.v.Type() {
|
||||||
|
case int32Type:
|
||||||
|
p.v.SetInt(int64(x))
|
||||||
|
return
|
||||||
|
case uint32Type:
|
||||||
|
p.v.SetUint(uint64(x))
|
||||||
|
return
|
||||||
|
case float32Type:
|
||||||
|
p.v.SetFloat(float64(math.Float32frombits(x)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be enum
|
||||||
|
p.v.SetInt(int64(int32(x)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the bits pointed at by p, as a uint32.
|
||||||
|
func word32Val_Get(p word32Val) uint32 {
|
||||||
|
elem := p.v
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int32:
|
||||||
|
return uint32(elem.Int())
|
||||||
|
case reflect.Uint32:
|
||||||
|
return uint32(elem.Uint())
|
||||||
|
case reflect.Float32:
|
||||||
|
return math.Float32bits(float32(elem.Float()))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32Val returns a reference to a int32, uint32, float32, or enum field in the struct.
|
||||||
|
func structPointer_Word32Val(p structPointer, f field) word32Val {
|
||||||
|
return word32Val{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A word32Slice is a slice of 32-bit values.
|
||||||
|
// That is, v.Type() is []int32, []uint32, []float32, or []enum.
|
||||||
|
type word32Slice struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word32Slice) Append(x uint32) {
|
||||||
|
n, m := p.v.Len(), p.v.Cap()
|
||||||
|
if n < m {
|
||||||
|
p.v.SetLen(n + 1)
|
||||||
|
} else {
|
||||||
|
t := p.v.Type().Elem()
|
||||||
|
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
|
||||||
|
}
|
||||||
|
elem := p.v.Index(n)
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int32:
|
||||||
|
elem.SetInt(int64(int32(x)))
|
||||||
|
case reflect.Uint32:
|
||||||
|
elem.SetUint(uint64(x))
|
||||||
|
case reflect.Float32:
|
||||||
|
elem.SetFloat(float64(math.Float32frombits(x)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word32Slice) Len() int {
|
||||||
|
return p.v.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word32Slice) Index(i int) uint32 {
|
||||||
|
elem := p.v.Index(i)
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int32:
|
||||||
|
return uint32(elem.Int())
|
||||||
|
case reflect.Uint32:
|
||||||
|
return uint32(elem.Uint())
|
||||||
|
case reflect.Float32:
|
||||||
|
return math.Float32bits(float32(elem.Float()))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32Slice returns a reference to a []int32, []uint32, []float32, or []enum field in the struct.
|
||||||
|
func structPointer_Word32Slice(p structPointer, f field) word32Slice {
|
||||||
|
return word32Slice{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64 is like word32 but for 64-bit values.
|
||||||
|
type word64 struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_Set(p word64, o *Buffer, x uint64) {
|
||||||
|
t := p.v.Type().Elem()
|
||||||
|
switch t {
|
||||||
|
case int64Type:
|
||||||
|
if len(o.int64s) == 0 {
|
||||||
|
o.int64s = make([]int64, uint64PoolSize)
|
||||||
|
}
|
||||||
|
o.int64s[0] = int64(x)
|
||||||
|
p.v.Set(reflect.ValueOf(&o.int64s[0]))
|
||||||
|
o.int64s = o.int64s[1:]
|
||||||
|
return
|
||||||
|
case uint64Type:
|
||||||
|
if len(o.uint64s) == 0 {
|
||||||
|
o.uint64s = make([]uint64, uint64PoolSize)
|
||||||
|
}
|
||||||
|
o.uint64s[0] = x
|
||||||
|
p.v.Set(reflect.ValueOf(&o.uint64s[0]))
|
||||||
|
o.uint64s = o.uint64s[1:]
|
||||||
|
return
|
||||||
|
case float64Type:
|
||||||
|
if len(o.float64s) == 0 {
|
||||||
|
o.float64s = make([]float64, uint64PoolSize)
|
||||||
|
}
|
||||||
|
o.float64s[0] = math.Float64frombits(x)
|
||||||
|
p.v.Set(reflect.ValueOf(&o.float64s[0]))
|
||||||
|
o.float64s = o.float64s[1:]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_IsNil(p word64) bool {
|
||||||
|
return p.v.IsNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_Get(p word64) uint64 {
|
||||||
|
elem := p.v.Elem()
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
return uint64(elem.Int())
|
||||||
|
case reflect.Uint64:
|
||||||
|
return elem.Uint()
|
||||||
|
case reflect.Float64:
|
||||||
|
return math.Float64bits(elem.Float())
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64(p structPointer, f field) word64 {
|
||||||
|
return word64{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64Val is like word32Val but for 64-bit values.
|
||||||
|
type word64Val struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64Val_Set(p word64Val, o *Buffer, x uint64) {
|
||||||
|
switch p.v.Type() {
|
||||||
|
case int64Type:
|
||||||
|
p.v.SetInt(int64(x))
|
||||||
|
return
|
||||||
|
case uint64Type:
|
||||||
|
p.v.SetUint(x)
|
||||||
|
return
|
||||||
|
case float64Type:
|
||||||
|
p.v.SetFloat(math.Float64frombits(x))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64Val_Get(p word64Val) uint64 {
|
||||||
|
elem := p.v
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
return uint64(elem.Int())
|
||||||
|
case reflect.Uint64:
|
||||||
|
return elem.Uint()
|
||||||
|
case reflect.Float64:
|
||||||
|
return math.Float64bits(elem.Float())
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64Val(p structPointer, f field) word64Val {
|
||||||
|
return word64Val{structPointer_field(p, f)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type word64Slice struct {
|
||||||
|
v reflect.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word64Slice) Append(x uint64) {
|
||||||
|
n, m := p.v.Len(), p.v.Cap()
|
||||||
|
if n < m {
|
||||||
|
p.v.SetLen(n + 1)
|
||||||
|
} else {
|
||||||
|
t := p.v.Type().Elem()
|
||||||
|
p.v.Set(reflect.Append(p.v, reflect.Zero(t)))
|
||||||
|
}
|
||||||
|
elem := p.v.Index(n)
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
elem.SetInt(int64(int64(x)))
|
||||||
|
case reflect.Uint64:
|
||||||
|
elem.SetUint(uint64(x))
|
||||||
|
case reflect.Float64:
|
||||||
|
elem.SetFloat(float64(math.Float64frombits(x)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word64Slice) Len() int {
|
||||||
|
return p.v.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p word64Slice) Index(i int) uint64 {
|
||||||
|
elem := p.v.Index(i)
|
||||||
|
switch elem.Kind() {
|
||||||
|
case reflect.Int64:
|
||||||
|
return uint64(elem.Int())
|
||||||
|
case reflect.Uint64:
|
||||||
|
return uint64(elem.Uint())
|
||||||
|
case reflect.Float64:
|
||||||
|
return math.Float64bits(float64(elem.Float()))
|
||||||
|
}
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64Slice(p structPointer, f field) word64Slice {
|
||||||
|
return word64Slice{structPointer_field(p, f)}
|
||||||
|
}
|
270
vendor/github.com/golang/protobuf/proto/pointer_unsafe.go
generated
vendored
Normal file
270
vendor/github.com/golang/protobuf/proto/pointer_unsafe.go
generated
vendored
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
// +build !appengine,!js
|
||||||
|
|
||||||
|
// This file contains the implementation of the proto field accesses using package unsafe.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: These type_Foo functions would more idiomatically be methods,
|
||||||
|
// but Go does not allow methods on pointer types, and we must preserve
|
||||||
|
// some pointer type for the garbage collector. We use these
|
||||||
|
// funcs with clunky names as our poor approximation to methods.
|
||||||
|
//
|
||||||
|
// An alternative would be
|
||||||
|
// type structPointer struct { p unsafe.Pointer }
|
||||||
|
// but that does not registerize as well.
|
||||||
|
|
||||||
|
// A structPointer is a pointer to a struct.
|
||||||
|
type structPointer unsafe.Pointer
|
||||||
|
|
||||||
|
// toStructPointer returns a structPointer equivalent to the given reflect value.
|
||||||
|
func toStructPointer(v reflect.Value) structPointer {
|
||||||
|
return structPointer(unsafe.Pointer(v.Pointer()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNil reports whether p is nil.
|
||||||
|
func structPointer_IsNil(p structPointer) bool {
|
||||||
|
return p == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface returns the struct pointer, assumed to have element type t,
|
||||||
|
// as an interface value.
|
||||||
|
func structPointer_Interface(p structPointer, t reflect.Type) interface{} {
|
||||||
|
return reflect.NewAt(t, unsafe.Pointer(p)).Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A field identifies a field in a struct, accessible from a structPointer.
|
||||||
|
// In this implementation, a field is identified by its byte offset from the start of the struct.
|
||||||
|
type field uintptr
|
||||||
|
|
||||||
|
// toField returns a field equivalent to the given reflect field.
|
||||||
|
func toField(f *reflect.StructField) field {
|
||||||
|
return field(f.Offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidField is an invalid field identifier.
|
||||||
|
const invalidField = ^field(0)
|
||||||
|
|
||||||
|
// IsValid reports whether the field identifier is valid.
|
||||||
|
func (f field) IsValid() bool {
|
||||||
|
return f != ^field(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the address of a []byte field in the struct.
|
||||||
|
func structPointer_Bytes(p structPointer, f field) *[]byte {
|
||||||
|
return (*[]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesSlice returns the address of a [][]byte field in the struct.
|
||||||
|
func structPointer_BytesSlice(p structPointer, f field) *[][]byte {
|
||||||
|
return (*[][]byte)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool returns the address of a *bool field in the struct.
|
||||||
|
func structPointer_Bool(p structPointer, f field) **bool {
|
||||||
|
return (**bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolVal returns the address of a bool field in the struct.
|
||||||
|
func structPointer_BoolVal(p structPointer, f field) *bool {
|
||||||
|
return (*bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolSlice returns the address of a []bool field in the struct.
|
||||||
|
func structPointer_BoolSlice(p structPointer, f field) *[]bool {
|
||||||
|
return (*[]bool)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the address of a *string field in the struct.
|
||||||
|
func structPointer_String(p structPointer, f field) **string {
|
||||||
|
return (**string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringVal returns the address of a string field in the struct.
|
||||||
|
func structPointer_StringVal(p structPointer, f field) *string {
|
||||||
|
return (*string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringSlice returns the address of a []string field in the struct.
|
||||||
|
func structPointer_StringSlice(p structPointer, f field) *[]string {
|
||||||
|
return (*[]string)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtMap returns the address of an extension map field in the struct.
|
||||||
|
func structPointer_Extensions(p structPointer, f field) *XXX_InternalExtensions {
|
||||||
|
return (*XXX_InternalExtensions)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
|
||||||
|
return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAt returns the reflect.Value for a pointer to a field in the struct.
|
||||||
|
func structPointer_NewAt(p structPointer, f field, typ reflect.Type) reflect.Value {
|
||||||
|
return reflect.NewAt(typ, unsafe.Pointer(uintptr(p)+uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetStructPointer writes a *struct field in the struct.
|
||||||
|
func structPointer_SetStructPointer(p structPointer, f field, q structPointer) {
|
||||||
|
*(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f))) = q
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStructPointer reads a *struct field in the struct.
|
||||||
|
func structPointer_GetStructPointer(p structPointer, f field) structPointer {
|
||||||
|
return *(*structPointer)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructPointerSlice the address of a []*struct field in the struct.
|
||||||
|
func structPointer_StructPointerSlice(p structPointer, f field) *structPointerSlice {
|
||||||
|
return (*structPointerSlice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A structPointerSlice represents a slice of pointers to structs (themselves submessages or groups).
|
||||||
|
type structPointerSlice []structPointer
|
||||||
|
|
||||||
|
func (v *structPointerSlice) Len() int { return len(*v) }
|
||||||
|
func (v *structPointerSlice) Index(i int) structPointer { return (*v)[i] }
|
||||||
|
func (v *structPointerSlice) Append(p structPointer) { *v = append(*v, p) }
|
||||||
|
|
||||||
|
// A word32 is the address of a "pointer to 32-bit value" field.
|
||||||
|
type word32 **uint32
|
||||||
|
|
||||||
|
// IsNil reports whether *v is nil.
|
||||||
|
func word32_IsNil(p word32) bool {
|
||||||
|
return *p == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets *v to point at a newly allocated word set to x.
|
||||||
|
func word32_Set(p word32, o *Buffer, x uint32) {
|
||||||
|
if len(o.uint32s) == 0 {
|
||||||
|
o.uint32s = make([]uint32, uint32PoolSize)
|
||||||
|
}
|
||||||
|
o.uint32s[0] = x
|
||||||
|
*p = &o.uint32s[0]
|
||||||
|
o.uint32s = o.uint32s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the value pointed at by *v.
|
||||||
|
func word32_Get(p word32) uint32 {
|
||||||
|
return **p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32 returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
|
||||||
|
func structPointer_Word32(p structPointer, f field) word32 {
|
||||||
|
return word32((**uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A word32Val is the address of a 32-bit value field.
|
||||||
|
type word32Val *uint32
|
||||||
|
|
||||||
|
// Set sets *p to x.
|
||||||
|
func word32Val_Set(p word32Val, x uint32) {
|
||||||
|
*p = x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the value pointed at by p.
|
||||||
|
func word32Val_Get(p word32Val) uint32 {
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word32Val returns the address of a *int32, *uint32, *float32, or *enum field in the struct.
|
||||||
|
func structPointer_Word32Val(p structPointer, f field) word32Val {
|
||||||
|
return word32Val((*uint32)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A word32Slice is a slice of 32-bit values.
|
||||||
|
type word32Slice []uint32
|
||||||
|
|
||||||
|
func (v *word32Slice) Append(x uint32) { *v = append(*v, x) }
|
||||||
|
func (v *word32Slice) Len() int { return len(*v) }
|
||||||
|
func (v *word32Slice) Index(i int) uint32 { return (*v)[i] }
|
||||||
|
|
||||||
|
// Word32Slice returns the address of a []int32, []uint32, []float32, or []enum field in the struct.
|
||||||
|
func structPointer_Word32Slice(p structPointer, f field) *word32Slice {
|
||||||
|
return (*word32Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64 is like word32 but for 64-bit values.
|
||||||
|
type word64 **uint64
|
||||||
|
|
||||||
|
func word64_Set(p word64, o *Buffer, x uint64) {
|
||||||
|
if len(o.uint64s) == 0 {
|
||||||
|
o.uint64s = make([]uint64, uint64PoolSize)
|
||||||
|
}
|
||||||
|
o.uint64s[0] = x
|
||||||
|
*p = &o.uint64s[0]
|
||||||
|
o.uint64s = o.uint64s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_IsNil(p word64) bool {
|
||||||
|
return *p == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64_Get(p word64) uint64 {
|
||||||
|
return **p
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64(p structPointer, f field) word64 {
|
||||||
|
return word64((**uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64Val is like word32Val but for 64-bit values.
|
||||||
|
type word64Val *uint64
|
||||||
|
|
||||||
|
func word64Val_Set(p word64Val, o *Buffer, x uint64) {
|
||||||
|
*p = x
|
||||||
|
}
|
||||||
|
|
||||||
|
func word64Val_Get(p word64Val) uint64 {
|
||||||
|
return *p
|
||||||
|
}
|
||||||
|
|
||||||
|
func structPointer_Word64Val(p structPointer, f field) word64Val {
|
||||||
|
return word64Val((*uint64)(unsafe.Pointer(uintptr(p) + uintptr(f))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// word64Slice is like word32Slice but for 64-bit values.
|
||||||
|
type word64Slice []uint64
|
||||||
|
|
||||||
|
func (v *word64Slice) Append(x uint64) { *v = append(*v, x) }
|
||||||
|
func (v *word64Slice) Len() int { return len(*v) }
|
||||||
|
func (v *word64Slice) Index(i int) uint64 { return (*v)[i] }
|
||||||
|
|
||||||
|
func structPointer_Word64Slice(p structPointer, f field) *word64Slice {
|
||||||
|
return (*word64Slice)(unsafe.Pointer(uintptr(p) + uintptr(f)))
|
||||||
|
}
|
872
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
Normal file
872
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
Normal file
|
@ -0,0 +1,872 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Routines for encoding data into the wire format for protocol buffers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const debug bool = false
|
||||||
|
|
||||||
|
// Constants that identify the encoding of a value on the wire.
|
||||||
|
const (
|
||||||
|
WireVarint = 0
|
||||||
|
WireFixed64 = 1
|
||||||
|
WireBytes = 2
|
||||||
|
WireStartGroup = 3
|
||||||
|
WireEndGroup = 4
|
||||||
|
WireFixed32 = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
const startSize = 10 // initial slice/string sizes
|
||||||
|
|
||||||
|
// Encoders are defined in encode.go
|
||||||
|
// An encoder outputs the full representation of a field, including its
|
||||||
|
// tag and encoder type.
|
||||||
|
type encoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||||
|
|
||||||
|
// A valueEncoder encodes a single integer in a particular encoding.
|
||||||
|
type valueEncoder func(o *Buffer, x uint64) error
|
||||||
|
|
||||||
|
// Sizers are defined in encode.go
|
||||||
|
// A sizer returns the encoded size of a field, including its tag and encoder
|
||||||
|
// type.
|
||||||
|
type sizer func(prop *Properties, base structPointer) int
|
||||||
|
|
||||||
|
// A valueSizer returns the encoded size of a single integer in a particular
|
||||||
|
// encoding.
|
||||||
|
type valueSizer func(x uint64) int
|
||||||
|
|
||||||
|
// Decoders are defined in decode.go
|
||||||
|
// A decoder creates a value from its wire representation.
|
||||||
|
// Unrecognized subelements are saved in unrec.
|
||||||
|
type decoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||||
|
|
||||||
|
// A valueDecoder decodes a single integer in a particular encoding.
|
||||||
|
type valueDecoder func(o *Buffer) (x uint64, err error)
|
||||||
|
|
||||||
|
// A oneofMarshaler does the marshaling for all oneof fields in a message.
|
||||||
|
type oneofMarshaler func(Message, *Buffer) error
|
||||||
|
|
||||||
|
// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
|
||||||
|
type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
|
||||||
|
|
||||||
|
// A oneofSizer does the sizing for all oneof fields in a message.
|
||||||
|
type oneofSizer func(Message) int
|
||||||
|
|
||||||
|
// tagMap is an optimization over map[int]int for typical protocol buffer
|
||||||
|
// use-cases. Encoded protocol buffers are often in tag order with small tag
|
||||||
|
// numbers.
|
||||||
|
type tagMap struct {
|
||||||
|
fastTags []int
|
||||||
|
slowTags map[int]int
|
||||||
|
}
|
||||||
|
|
||||||
|
// tagMapFastLimit is the upper bound on the tag number that will be stored in
|
||||||
|
// the tagMap slice rather than its map.
|
||||||
|
const tagMapFastLimit = 1024
|
||||||
|
|
||||||
|
func (p *tagMap) get(t int) (int, bool) {
|
||||||
|
if t > 0 && t < tagMapFastLimit {
|
||||||
|
if t >= len(p.fastTags) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
fi := p.fastTags[t]
|
||||||
|
return fi, fi >= 0
|
||||||
|
}
|
||||||
|
fi, ok := p.slowTags[t]
|
||||||
|
return fi, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *tagMap) put(t int, fi int) {
|
||||||
|
if t > 0 && t < tagMapFastLimit {
|
||||||
|
for len(p.fastTags) < t+1 {
|
||||||
|
p.fastTags = append(p.fastTags, -1)
|
||||||
|
}
|
||||||
|
p.fastTags[t] = fi
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.slowTags == nil {
|
||||||
|
p.slowTags = make(map[int]int)
|
||||||
|
}
|
||||||
|
p.slowTags[t] = fi
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructProperties represents properties for all the fields of a struct.
|
||||||
|
// decoderTags and decoderOrigNames should only be used by the decoder.
|
||||||
|
type StructProperties struct {
|
||||||
|
Prop []*Properties // properties for each field
|
||||||
|
reqCount int // required count
|
||||||
|
decoderTags tagMap // map from proto tag to struct field number
|
||||||
|
decoderOrigNames map[string]int // map from original name to struct field number
|
||||||
|
order []int // list of struct field numbers in tag order
|
||||||
|
unrecField field // field id of the XXX_unrecognized []byte field
|
||||||
|
extendable bool // is this an extendable proto
|
||||||
|
|
||||||
|
oneofMarshaler oneofMarshaler
|
||||||
|
oneofUnmarshaler oneofUnmarshaler
|
||||||
|
oneofSizer oneofSizer
|
||||||
|
stype reflect.Type
|
||||||
|
|
||||||
|
// OneofTypes contains information about the oneof fields in this message.
|
||||||
|
// It is keyed by the original name of a field.
|
||||||
|
OneofTypes map[string]*OneofProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
// OneofProperties represents information about a specific field in a oneof.
|
||||||
|
type OneofProperties struct {
|
||||||
|
Type reflect.Type // pointer to generated struct type for this oneof field
|
||||||
|
Field int // struct field number of the containing oneof in the message
|
||||||
|
Prop *Properties
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
|
||||||
|
// See encode.go, (*Buffer).enc_struct.
|
||||||
|
|
||||||
|
func (sp *StructProperties) Len() int { return len(sp.order) }
|
||||||
|
func (sp *StructProperties) Less(i, j int) bool {
|
||||||
|
return sp.Prop[sp.order[i]].Tag < sp.Prop[sp.order[j]].Tag
|
||||||
|
}
|
||||||
|
func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order[j], sp.order[i] }
|
||||||
|
|
||||||
|
// Properties represents the protocol-specific behavior of a single struct field.
|
||||||
|
type Properties struct {
|
||||||
|
Name string // name of the field, for error messages
|
||||||
|
OrigName string // original name before protocol compiler (always set)
|
||||||
|
JSONName string // name to use for JSON; determined by protoc
|
||||||
|
Wire string
|
||||||
|
WireType int
|
||||||
|
Tag int
|
||||||
|
Required bool
|
||||||
|
Optional bool
|
||||||
|
Repeated bool
|
||||||
|
Packed bool // relevant for repeated primitives only
|
||||||
|
Enum string // set for enum types only
|
||||||
|
proto3 bool // whether this is known to be a proto3 field; set for []byte only
|
||||||
|
oneof bool // whether this is a oneof field
|
||||||
|
|
||||||
|
Default string // default value
|
||||||
|
HasDefault bool // whether an explicit default was provided
|
||||||
|
def_uint64 uint64
|
||||||
|
|
||||||
|
enc encoder
|
||||||
|
valEnc valueEncoder // set for bool and numeric types only
|
||||||
|
field field
|
||||||
|
tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
|
||||||
|
tagbuf [8]byte
|
||||||
|
stype reflect.Type // set for struct types only
|
||||||
|
sprop *StructProperties // set for struct types only
|
||||||
|
isMarshaler bool
|
||||||
|
isUnmarshaler bool
|
||||||
|
|
||||||
|
mtype reflect.Type // set for map types only
|
||||||
|
mkeyprop *Properties // set for map types only
|
||||||
|
mvalprop *Properties // set for map types only
|
||||||
|
|
||||||
|
size sizer
|
||||||
|
valSize valueSizer // set for bool and numeric types only
|
||||||
|
|
||||||
|
dec decoder
|
||||||
|
valDec valueDecoder // set for bool and numeric types only
|
||||||
|
|
||||||
|
// If this is a packable field, this will be the decoder for the packed version of the field.
|
||||||
|
packedDec decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// String formats the properties in the protobuf struct field tag style.
|
||||||
|
func (p *Properties) String() string {
|
||||||
|
s := p.Wire
|
||||||
|
s = ","
|
||||||
|
s += strconv.Itoa(p.Tag)
|
||||||
|
if p.Required {
|
||||||
|
s += ",req"
|
||||||
|
}
|
||||||
|
if p.Optional {
|
||||||
|
s += ",opt"
|
||||||
|
}
|
||||||
|
if p.Repeated {
|
||||||
|
s += ",rep"
|
||||||
|
}
|
||||||
|
if p.Packed {
|
||||||
|
s += ",packed"
|
||||||
|
}
|
||||||
|
s += ",name=" + p.OrigName
|
||||||
|
if p.JSONName != p.OrigName {
|
||||||
|
s += ",json=" + p.JSONName
|
||||||
|
}
|
||||||
|
if p.proto3 {
|
||||||
|
s += ",proto3"
|
||||||
|
}
|
||||||
|
if p.oneof {
|
||||||
|
s += ",oneof"
|
||||||
|
}
|
||||||
|
if len(p.Enum) > 0 {
|
||||||
|
s += ",enum=" + p.Enum
|
||||||
|
}
|
||||||
|
if p.HasDefault {
|
||||||
|
s += ",def=" + p.Default
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse populates p by parsing a string in the protobuf struct field tag style.
|
||||||
|
func (p *Properties) Parse(s string) {
|
||||||
|
// "bytes,49,opt,name=foo,def=hello!"
|
||||||
|
fields := strings.Split(s, ",") // breaks def=, but handled below.
|
||||||
|
if len(fields) < 2 {
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Wire = fields[0]
|
||||||
|
switch p.Wire {
|
||||||
|
case "varint":
|
||||||
|
p.WireType = WireVarint
|
||||||
|
p.valEnc = (*Buffer).EncodeVarint
|
||||||
|
p.valDec = (*Buffer).DecodeVarint
|
||||||
|
p.valSize = sizeVarint
|
||||||
|
case "fixed32":
|
||||||
|
p.WireType = WireFixed32
|
||||||
|
p.valEnc = (*Buffer).EncodeFixed32
|
||||||
|
p.valDec = (*Buffer).DecodeFixed32
|
||||||
|
p.valSize = sizeFixed32
|
||||||
|
case "fixed64":
|
||||||
|
p.WireType = WireFixed64
|
||||||
|
p.valEnc = (*Buffer).EncodeFixed64
|
||||||
|
p.valDec = (*Buffer).DecodeFixed64
|
||||||
|
p.valSize = sizeFixed64
|
||||||
|
case "zigzag32":
|
||||||
|
p.WireType = WireVarint
|
||||||
|
p.valEnc = (*Buffer).EncodeZigzag32
|
||||||
|
p.valDec = (*Buffer).DecodeZigzag32
|
||||||
|
p.valSize = sizeZigzag32
|
||||||
|
case "zigzag64":
|
||||||
|
p.WireType = WireVarint
|
||||||
|
p.valEnc = (*Buffer).EncodeZigzag64
|
||||||
|
p.valDec = (*Buffer).DecodeZigzag64
|
||||||
|
p.valSize = sizeZigzag64
|
||||||
|
case "bytes", "group":
|
||||||
|
p.WireType = WireBytes
|
||||||
|
// no numeric converter for non-numeric types
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
p.Tag, err = strconv.Atoi(fields[1])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 2; i < len(fields); i++ {
|
||||||
|
f := fields[i]
|
||||||
|
switch {
|
||||||
|
case f == "req":
|
||||||
|
p.Required = true
|
||||||
|
case f == "opt":
|
||||||
|
p.Optional = true
|
||||||
|
case f == "rep":
|
||||||
|
p.Repeated = true
|
||||||
|
case f == "packed":
|
||||||
|
p.Packed = true
|
||||||
|
case strings.HasPrefix(f, "name="):
|
||||||
|
p.OrigName = f[5:]
|
||||||
|
case strings.HasPrefix(f, "json="):
|
||||||
|
p.JSONName = f[5:]
|
||||||
|
case strings.HasPrefix(f, "enum="):
|
||||||
|
p.Enum = f[5:]
|
||||||
|
case f == "proto3":
|
||||||
|
p.proto3 = true
|
||||||
|
case f == "oneof":
|
||||||
|
p.oneof = true
|
||||||
|
case strings.HasPrefix(f, "def="):
|
||||||
|
p.HasDefault = true
|
||||||
|
p.Default = f[4:] // rest of string
|
||||||
|
if i+1 < len(fields) {
|
||||||
|
// Commas aren't escaped, and def is always last.
|
||||||
|
p.Default += "," + strings.Join(fields[i+1:], ",")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logNoSliceEnc(t1, t2 reflect.Type) {
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no slice oenc for %T = []%T\n", t1, t2)
|
||||||
|
}
|
||||||
|
|
||||||
|
var protoMessageType = reflect.TypeOf((*Message)(nil)).Elem()
|
||||||
|
|
||||||
|
// Initialize the fields for encoding and decoding.
|
||||||
|
func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lockGetProp bool) {
|
||||||
|
p.enc = nil
|
||||||
|
p.dec = nil
|
||||||
|
p.size = nil
|
||||||
|
|
||||||
|
switch t1 := typ; t1.Kind() {
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no coders for %v\n", t1)
|
||||||
|
|
||||||
|
// proto3 scalar types
|
||||||
|
|
||||||
|
case reflect.Bool:
|
||||||
|
p.enc = (*Buffer).enc_proto3_bool
|
||||||
|
p.dec = (*Buffer).dec_proto3_bool
|
||||||
|
p.size = size_proto3_bool
|
||||||
|
case reflect.Int32:
|
||||||
|
p.enc = (*Buffer).enc_proto3_int32
|
||||||
|
p.dec = (*Buffer).dec_proto3_int32
|
||||||
|
p.size = size_proto3_int32
|
||||||
|
case reflect.Uint32:
|
||||||
|
p.enc = (*Buffer).enc_proto3_uint32
|
||||||
|
p.dec = (*Buffer).dec_proto3_int32 // can reuse
|
||||||
|
p.size = size_proto3_uint32
|
||||||
|
case reflect.Int64, reflect.Uint64:
|
||||||
|
p.enc = (*Buffer).enc_proto3_int64
|
||||||
|
p.dec = (*Buffer).dec_proto3_int64
|
||||||
|
p.size = size_proto3_int64
|
||||||
|
case reflect.Float32:
|
||||||
|
p.enc = (*Buffer).enc_proto3_uint32 // can just treat them as bits
|
||||||
|
p.dec = (*Buffer).dec_proto3_int32
|
||||||
|
p.size = size_proto3_uint32
|
||||||
|
case reflect.Float64:
|
||||||
|
p.enc = (*Buffer).enc_proto3_int64 // can just treat them as bits
|
||||||
|
p.dec = (*Buffer).dec_proto3_int64
|
||||||
|
p.size = size_proto3_int64
|
||||||
|
case reflect.String:
|
||||||
|
p.enc = (*Buffer).enc_proto3_string
|
||||||
|
p.dec = (*Buffer).dec_proto3_string
|
||||||
|
p.size = size_proto3_string
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
switch t2 := t1.Elem(); t2.Kind() {
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no encoder function for %v -> %v\n", t1, t2)
|
||||||
|
break
|
||||||
|
case reflect.Bool:
|
||||||
|
p.enc = (*Buffer).enc_bool
|
||||||
|
p.dec = (*Buffer).dec_bool
|
||||||
|
p.size = size_bool
|
||||||
|
case reflect.Int32:
|
||||||
|
p.enc = (*Buffer).enc_int32
|
||||||
|
p.dec = (*Buffer).dec_int32
|
||||||
|
p.size = size_int32
|
||||||
|
case reflect.Uint32:
|
||||||
|
p.enc = (*Buffer).enc_uint32
|
||||||
|
p.dec = (*Buffer).dec_int32 // can reuse
|
||||||
|
p.size = size_uint32
|
||||||
|
case reflect.Int64, reflect.Uint64:
|
||||||
|
p.enc = (*Buffer).enc_int64
|
||||||
|
p.dec = (*Buffer).dec_int64
|
||||||
|
p.size = size_int64
|
||||||
|
case reflect.Float32:
|
||||||
|
p.enc = (*Buffer).enc_uint32 // can just treat them as bits
|
||||||
|
p.dec = (*Buffer).dec_int32
|
||||||
|
p.size = size_uint32
|
||||||
|
case reflect.Float64:
|
||||||
|
p.enc = (*Buffer).enc_int64 // can just treat them as bits
|
||||||
|
p.dec = (*Buffer).dec_int64
|
||||||
|
p.size = size_int64
|
||||||
|
case reflect.String:
|
||||||
|
p.enc = (*Buffer).enc_string
|
||||||
|
p.dec = (*Buffer).dec_string
|
||||||
|
p.size = size_string
|
||||||
|
case reflect.Struct:
|
||||||
|
p.stype = t1.Elem()
|
||||||
|
p.isMarshaler = isMarshaler(t1)
|
||||||
|
p.isUnmarshaler = isUnmarshaler(t1)
|
||||||
|
if p.Wire == "bytes" {
|
||||||
|
p.enc = (*Buffer).enc_struct_message
|
||||||
|
p.dec = (*Buffer).dec_struct_message
|
||||||
|
p.size = size_struct_message
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_struct_group
|
||||||
|
p.dec = (*Buffer).dec_struct_group
|
||||||
|
p.size = size_struct_group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Slice:
|
||||||
|
switch t2 := t1.Elem(); t2.Kind() {
|
||||||
|
default:
|
||||||
|
logNoSliceEnc(t1, t2)
|
||||||
|
break
|
||||||
|
case reflect.Bool:
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_bool
|
||||||
|
p.size = size_slice_packed_bool
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_bool
|
||||||
|
p.size = size_slice_bool
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_bool
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_bool
|
||||||
|
case reflect.Int32:
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_int32
|
||||||
|
p.size = size_slice_packed_int32
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_int32
|
||||||
|
p.size = size_slice_int32
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int32
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||||
|
case reflect.Uint32:
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_uint32
|
||||||
|
p.size = size_slice_packed_uint32
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_uint32
|
||||||
|
p.size = size_slice_uint32
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int32
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||||
|
case reflect.Int64, reflect.Uint64:
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_int64
|
||||||
|
p.size = size_slice_packed_int64
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_int64
|
||||||
|
p.size = size_slice_int64
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int64
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int64
|
||||||
|
case reflect.Uint8:
|
||||||
|
p.dec = (*Buffer).dec_slice_byte
|
||||||
|
if p.proto3 {
|
||||||
|
p.enc = (*Buffer).enc_proto3_slice_byte
|
||||||
|
p.size = size_proto3_slice_byte
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_byte
|
||||||
|
p.size = size_slice_byte
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
switch t2.Bits() {
|
||||||
|
case 32:
|
||||||
|
// can just treat them as bits
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_uint32
|
||||||
|
p.size = size_slice_packed_uint32
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_uint32
|
||||||
|
p.size = size_slice_uint32
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int32
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int32
|
||||||
|
case 64:
|
||||||
|
// can just treat them as bits
|
||||||
|
if p.Packed {
|
||||||
|
p.enc = (*Buffer).enc_slice_packed_int64
|
||||||
|
p.size = size_slice_packed_int64
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_int64
|
||||||
|
p.size = size_slice_int64
|
||||||
|
}
|
||||||
|
p.dec = (*Buffer).dec_slice_int64
|
||||||
|
p.packedDec = (*Buffer).dec_slice_packed_int64
|
||||||
|
default:
|
||||||
|
logNoSliceEnc(t1, t2)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
p.enc = (*Buffer).enc_slice_string
|
||||||
|
p.dec = (*Buffer).dec_slice_string
|
||||||
|
p.size = size_slice_string
|
||||||
|
case reflect.Ptr:
|
||||||
|
switch t3 := t2.Elem(); t3.Kind() {
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no ptr oenc for %T -> %T -> %T\n", t1, t2, t3)
|
||||||
|
break
|
||||||
|
case reflect.Struct:
|
||||||
|
p.stype = t2.Elem()
|
||||||
|
p.isMarshaler = isMarshaler(t2)
|
||||||
|
p.isUnmarshaler = isUnmarshaler(t2)
|
||||||
|
if p.Wire == "bytes" {
|
||||||
|
p.enc = (*Buffer).enc_slice_struct_message
|
||||||
|
p.dec = (*Buffer).dec_slice_struct_message
|
||||||
|
p.size = size_slice_struct_message
|
||||||
|
} else {
|
||||||
|
p.enc = (*Buffer).enc_slice_struct_group
|
||||||
|
p.dec = (*Buffer).dec_slice_struct_group
|
||||||
|
p.size = size_slice_struct_group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case reflect.Slice:
|
||||||
|
switch t2.Elem().Kind() {
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: no slice elem oenc for %T -> %T -> %T\n", t1, t2, t2.Elem())
|
||||||
|
break
|
||||||
|
case reflect.Uint8:
|
||||||
|
p.enc = (*Buffer).enc_slice_slice_byte
|
||||||
|
p.dec = (*Buffer).dec_slice_slice_byte
|
||||||
|
p.size = size_slice_slice_byte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Map:
|
||||||
|
p.enc = (*Buffer).enc_new_map
|
||||||
|
p.dec = (*Buffer).dec_new_map
|
||||||
|
p.size = size_new_map
|
||||||
|
|
||||||
|
p.mtype = t1
|
||||||
|
p.mkeyprop = &Properties{}
|
||||||
|
p.mkeyprop.init(reflect.PtrTo(p.mtype.Key()), "Key", f.Tag.Get("protobuf_key"), nil, lockGetProp)
|
||||||
|
p.mvalprop = &Properties{}
|
||||||
|
vtype := p.mtype.Elem()
|
||||||
|
if vtype.Kind() != reflect.Ptr && vtype.Kind() != reflect.Slice {
|
||||||
|
// The value type is not a message (*T) or bytes ([]byte),
|
||||||
|
// so we need encoders for the pointer to this type.
|
||||||
|
vtype = reflect.PtrTo(vtype)
|
||||||
|
}
|
||||||
|
p.mvalprop.init(vtype, "Value", f.Tag.Get("protobuf_val"), nil, lockGetProp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// precalculate tag code
|
||||||
|
wire := p.WireType
|
||||||
|
if p.Packed {
|
||||||
|
wire = WireBytes
|
||||||
|
}
|
||||||
|
x := uint32(p.Tag)<<3 | uint32(wire)
|
||||||
|
i := 0
|
||||||
|
for i = 0; x > 127; i++ {
|
||||||
|
p.tagbuf[i] = 0x80 | uint8(x&0x7F)
|
||||||
|
x >>= 7
|
||||||
|
}
|
||||||
|
p.tagbuf[i] = uint8(x)
|
||||||
|
p.tagcode = p.tagbuf[0 : i+1]
|
||||||
|
|
||||||
|
if p.stype != nil {
|
||||||
|
if lockGetProp {
|
||||||
|
p.sprop = GetProperties(p.stype)
|
||||||
|
} else {
|
||||||
|
p.sprop = getPropertiesLocked(p.stype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
|
||||||
|
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||||
|
)
|
||||||
|
|
||||||
|
// isMarshaler reports whether type t implements Marshaler.
|
||||||
|
func isMarshaler(t reflect.Type) bool {
|
||||||
|
// We're checking for (likely) pointer-receiver methods
|
||||||
|
// so if t is not a pointer, something is very wrong.
|
||||||
|
// The calls above only invoke isMarshaler on pointer types.
|
||||||
|
if t.Kind() != reflect.Ptr {
|
||||||
|
panic("proto: misuse of isMarshaler")
|
||||||
|
}
|
||||||
|
return t.Implements(marshalerType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isUnmarshaler reports whether type t implements Unmarshaler.
|
||||||
|
func isUnmarshaler(t reflect.Type) bool {
|
||||||
|
// We're checking for (likely) pointer-receiver methods
|
||||||
|
// so if t is not a pointer, something is very wrong.
|
||||||
|
// The calls above only invoke isUnmarshaler on pointer types.
|
||||||
|
if t.Kind() != reflect.Ptr {
|
||||||
|
panic("proto: misuse of isUnmarshaler")
|
||||||
|
}
|
||||||
|
return t.Implements(unmarshalerType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init populates the properties from a protocol buffer struct tag.
|
||||||
|
func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
|
||||||
|
p.init(typ, name, tag, f, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField, lockGetProp bool) {
|
||||||
|
// "bytes,49,opt,def=hello!"
|
||||||
|
p.Name = name
|
||||||
|
p.OrigName = name
|
||||||
|
if f != nil {
|
||||||
|
p.field = toField(f)
|
||||||
|
}
|
||||||
|
if tag == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Parse(tag)
|
||||||
|
p.setEncAndDec(typ, f, lockGetProp)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
propertiesMu sync.RWMutex
|
||||||
|
propertiesMap = make(map[reflect.Type]*StructProperties)
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetProperties returns the list of properties for the type represented by t.
|
||||||
|
// t must represent a generated struct type of a protocol message.
|
||||||
|
func GetProperties(t reflect.Type) *StructProperties {
|
||||||
|
if t.Kind() != reflect.Struct {
|
||||||
|
panic("proto: type must have kind struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Most calls to GetProperties in a long-running program will be
|
||||||
|
// retrieving details for types we have seen before.
|
||||||
|
propertiesMu.RLock()
|
||||||
|
sprop, ok := propertiesMap[t]
|
||||||
|
propertiesMu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
if collectStats {
|
||||||
|
stats.Chit++
|
||||||
|
}
|
||||||
|
return sprop
|
||||||
|
}
|
||||||
|
|
||||||
|
propertiesMu.Lock()
|
||||||
|
sprop = getPropertiesLocked(t)
|
||||||
|
propertiesMu.Unlock()
|
||||||
|
return sprop
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPropertiesLocked requires that propertiesMu is held.
|
||||||
|
func getPropertiesLocked(t reflect.Type) *StructProperties {
|
||||||
|
if prop, ok := propertiesMap[t]; ok {
|
||||||
|
if collectStats {
|
||||||
|
stats.Chit++
|
||||||
|
}
|
||||||
|
return prop
|
||||||
|
}
|
||||||
|
if collectStats {
|
||||||
|
stats.Cmiss++
|
||||||
|
}
|
||||||
|
|
||||||
|
prop := new(StructProperties)
|
||||||
|
// in case of recursive protos, fill this in now.
|
||||||
|
propertiesMap[t] = prop
|
||||||
|
|
||||||
|
// build properties
|
||||||
|
prop.extendable = reflect.PtrTo(t).Implements(extendableProtoType) ||
|
||||||
|
reflect.PtrTo(t).Implements(extendableProtoV1Type)
|
||||||
|
prop.unrecField = invalidField
|
||||||
|
prop.Prop = make([]*Properties, t.NumField())
|
||||||
|
prop.order = make([]int, t.NumField())
|
||||||
|
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
f := t.Field(i)
|
||||||
|
p := new(Properties)
|
||||||
|
name := f.Name
|
||||||
|
p.init(f.Type, name, f.Tag.Get("protobuf"), &f, false)
|
||||||
|
|
||||||
|
if f.Name == "XXX_InternalExtensions" { // special case
|
||||||
|
p.enc = (*Buffer).enc_exts
|
||||||
|
p.dec = nil // not needed
|
||||||
|
p.size = size_exts
|
||||||
|
} else if f.Name == "XXX_extensions" { // special case
|
||||||
|
p.enc = (*Buffer).enc_map
|
||||||
|
p.dec = nil // not needed
|
||||||
|
p.size = size_map
|
||||||
|
} else if f.Name == "XXX_unrecognized" { // special case
|
||||||
|
prop.unrecField = toField(&f)
|
||||||
|
}
|
||||||
|
oneof := f.Tag.Get("protobuf_oneof") // special case
|
||||||
|
if oneof != "" {
|
||||||
|
// Oneof fields don't use the traditional protobuf tag.
|
||||||
|
p.OrigName = oneof
|
||||||
|
}
|
||||||
|
prop.Prop[i] = p
|
||||||
|
prop.order[i] = i
|
||||||
|
if debug {
|
||||||
|
print(i, " ", f.Name, " ", t.String(), " ")
|
||||||
|
if p.Tag > 0 {
|
||||||
|
print(p.String())
|
||||||
|
}
|
||||||
|
print("\n")
|
||||||
|
}
|
||||||
|
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && oneof == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-order prop.order.
|
||||||
|
sort.Sort(prop)
|
||||||
|
|
||||||
|
type oneofMessage interface {
|
||||||
|
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
|
||||||
|
}
|
||||||
|
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
|
||||||
|
var oots []interface{}
|
||||||
|
prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
|
||||||
|
prop.stype = t
|
||||||
|
|
||||||
|
// Interpret oneof metadata.
|
||||||
|
prop.OneofTypes = make(map[string]*OneofProperties)
|
||||||
|
for _, oot := range oots {
|
||||||
|
oop := &OneofProperties{
|
||||||
|
Type: reflect.ValueOf(oot).Type(), // *T
|
||||||
|
Prop: new(Properties),
|
||||||
|
}
|
||||||
|
sft := oop.Type.Elem().Field(0)
|
||||||
|
oop.Prop.Name = sft.Name
|
||||||
|
oop.Prop.Parse(sft.Tag.Get("protobuf"))
|
||||||
|
// There will be exactly one interface field that
|
||||||
|
// this new value is assignable to.
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
f := t.Field(i)
|
||||||
|
if f.Type.Kind() != reflect.Interface {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !oop.Type.AssignableTo(f.Type) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
oop.Field = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
prop.OneofTypes[oop.Prop.OrigName] = oop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build required counts
|
||||||
|
// build tags
|
||||||
|
reqCount := 0
|
||||||
|
prop.decoderOrigNames = make(map[string]int)
|
||||||
|
for i, p := range prop.Prop {
|
||||||
|
if strings.HasPrefix(p.Name, "XXX_") {
|
||||||
|
// Internal fields should not appear in tags/origNames maps.
|
||||||
|
// They are handled specially when encoding and decoding.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if p.Required {
|
||||||
|
reqCount++
|
||||||
|
}
|
||||||
|
prop.decoderTags.put(p.Tag, i)
|
||||||
|
prop.decoderOrigNames[p.OrigName] = i
|
||||||
|
}
|
||||||
|
prop.reqCount = reqCount
|
||||||
|
|
||||||
|
return prop
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the Properties object for the x[0]'th field of the structure.
|
||||||
|
func propByIndex(t reflect.Type, x []int) *Properties {
|
||||||
|
if len(x) != 1 {
|
||||||
|
fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
prop := GetProperties(t)
|
||||||
|
return prop.Prop[x[0]]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the address and type of a pointer to a struct from an interface.
|
||||||
|
func getbase(pb Message) (t reflect.Type, b structPointer, err error) {
|
||||||
|
if pb == nil {
|
||||||
|
err = ErrNil
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// get the reflect type of the pointer to the struct.
|
||||||
|
t = reflect.TypeOf(pb)
|
||||||
|
// get the address of the struct.
|
||||||
|
value := reflect.ValueOf(pb)
|
||||||
|
b = toStructPointer(value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// A global registry of enum types.
|
||||||
|
// The generated code will register the generated maps by calling RegisterEnum.
|
||||||
|
|
||||||
|
var enumValueMaps = make(map[string]map[string]int32)
|
||||||
|
|
||||||
|
// RegisterEnum is called from the generated code to install the enum descriptor
|
||||||
|
// maps into the global table to aid parsing text format protocol buffers.
|
||||||
|
func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[string]int32) {
|
||||||
|
if _, ok := enumValueMaps[typeName]; ok {
|
||||||
|
panic("proto: duplicate enum registered: " + typeName)
|
||||||
|
}
|
||||||
|
enumValueMaps[typeName] = valueMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnumValueMap returns the mapping from names to integers of the
|
||||||
|
// enum type enumType, or a nil if not found.
|
||||||
|
func EnumValueMap(enumType string) map[string]int32 {
|
||||||
|
return enumValueMaps[enumType]
|
||||||
|
}
|
||||||
|
|
||||||
|
// A registry of all linked message types.
|
||||||
|
// The string is a fully-qualified proto name ("pkg.Message").
|
||||||
|
var (
|
||||||
|
protoTypes = make(map[string]reflect.Type)
|
||||||
|
revProtoTypes = make(map[reflect.Type]string)
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterType is called from generated code and maps from the fully qualified
|
||||||
|
// proto name to the type (pointer to struct) of the protocol buffer.
|
||||||
|
func RegisterType(x Message, name string) {
|
||||||
|
if _, ok := protoTypes[name]; ok {
|
||||||
|
// TODO: Some day, make this a panic.
|
||||||
|
log.Printf("proto: duplicate proto type registered: %s", name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := reflect.TypeOf(x)
|
||||||
|
protoTypes[name] = t
|
||||||
|
revProtoTypes[t] = name
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageName returns the fully-qualified proto name for the given message type.
|
||||||
|
func MessageName(x Message) string {
|
||||||
|
type xname interface {
|
||||||
|
XXX_MessageName() string
|
||||||
|
}
|
||||||
|
if m, ok := x.(xname); ok {
|
||||||
|
return m.XXX_MessageName()
|
||||||
|
}
|
||||||
|
return revProtoTypes[reflect.TypeOf(x)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageType returns the message type (pointer to struct) for a named message.
|
||||||
|
func MessageType(name string) reflect.Type { return protoTypes[name] }
|
||||||
|
|
||||||
|
// A registry of all linked proto files.
|
||||||
|
var (
|
||||||
|
protoFiles = make(map[string][]byte) // file name => fileDescriptor
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterFile is called from generated code and maps from the
|
||||||
|
// full file name of a .proto file to its compressed FileDescriptorProto.
|
||||||
|
func RegisterFile(filename string, fileDescriptor []byte) {
|
||||||
|
protoFiles[filename] = fileDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileDescriptor returns the compressed FileDescriptorProto for a .proto file.
|
||||||
|
func FileDescriptor(filename string) []byte { return protoFiles[filename] }
|
854
vendor/github.com/golang/protobuf/proto/text.go
generated
vendored
Normal file
854
vendor/github.com/golang/protobuf/proto/text.go
generated
vendored
Normal file
|
@ -0,0 +1,854 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
// Functions for writing the text protocol buffer format.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"encoding"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
newline = []byte("\n")
|
||||||
|
spaces = []byte(" ")
|
||||||
|
gtNewline = []byte(">\n")
|
||||||
|
endBraceNewline = []byte("}\n")
|
||||||
|
backslashN = []byte{'\\', 'n'}
|
||||||
|
backslashR = []byte{'\\', 'r'}
|
||||||
|
backslashT = []byte{'\\', 't'}
|
||||||
|
backslashDQ = []byte{'\\', '"'}
|
||||||
|
backslashBS = []byte{'\\', '\\'}
|
||||||
|
posInf = []byte("inf")
|
||||||
|
negInf = []byte("-inf")
|
||||||
|
nan = []byte("nan")
|
||||||
|
)
|
||||||
|
|
||||||
|
type writer interface {
|
||||||
|
io.Writer
|
||||||
|
WriteByte(byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// textWriter is an io.Writer that tracks its indentation level.
|
||||||
|
type textWriter struct {
|
||||||
|
ind int
|
||||||
|
complete bool // if the current position is a complete line
|
||||||
|
compact bool // whether to write out as a one-liner
|
||||||
|
w writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *textWriter) WriteString(s string) (n int, err error) {
|
||||||
|
if !strings.Contains(s, "\n") {
|
||||||
|
if !w.compact && w.complete {
|
||||||
|
w.writeIndent()
|
||||||
|
}
|
||||||
|
w.complete = false
|
||||||
|
return io.WriteString(w.w, s)
|
||||||
|
}
|
||||||
|
// WriteString is typically called without newlines, so this
|
||||||
|
// codepath and its copy are rare. We copy to avoid
|
||||||
|
// duplicating all of Write's logic here.
|
||||||
|
return w.Write([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *textWriter) Write(p []byte) (n int, err error) {
|
||||||
|
newlines := bytes.Count(p, newline)
|
||||||
|
if newlines == 0 {
|
||||||
|
if !w.compact && w.complete {
|
||||||
|
w.writeIndent()
|
||||||
|
}
|
||||||
|
n, err = w.w.Write(p)
|
||||||
|
w.complete = false
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
frags := bytes.SplitN(p, newline, newlines+1)
|
||||||
|
if w.compact {
|
||||||
|
for i, frag := range frags {
|
||||||
|
if i > 0 {
|
||||||
|
if err := w.w.WriteByte(' '); err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
nn, err := w.w.Write(frag)
|
||||||
|
n += nn
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, frag := range frags {
|
||||||
|
if w.complete {
|
||||||
|
w.writeIndent()
|
||||||
|
}
|
||||||
|
nn, err := w.w.Write(frag)
|
||||||
|
n += nn
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
if i+1 < len(frags) {
|
||||||
|
if err := w.w.WriteByte('\n'); err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.complete = len(frags[len(frags)-1]) == 0
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *textWriter) WriteByte(c byte) error {
|
||||||
|
if w.compact && c == '\n' {
|
||||||
|
c = ' '
|
||||||
|
}
|
||||||
|
if !w.compact && w.complete {
|
||||||
|
w.writeIndent()
|
||||||
|
}
|
||||||
|
err := w.w.WriteByte(c)
|
||||||
|
w.complete = c == '\n'
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *textWriter) indent() { w.ind++ }
|
||||||
|
|
||||||
|
func (w *textWriter) unindent() {
|
||||||
|
if w.ind == 0 {
|
||||||
|
log.Print("proto: textWriter unindented too far")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.ind--
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeName(w *textWriter, props *Properties) error {
|
||||||
|
if _, err := w.WriteString(props.OrigName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if props.Wire != "group" {
|
||||||
|
return w.WriteByte(':')
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// raw is the interface satisfied by RawMessage.
|
||||||
|
type raw interface {
|
||||||
|
Bytes() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func requiresQuotes(u string) bool {
|
||||||
|
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
|
||||||
|
for _, ch := range u {
|
||||||
|
switch {
|
||||||
|
case ch == '.' || ch == '/' || ch == '_':
|
||||||
|
continue
|
||||||
|
case '0' <= ch && ch <= '9':
|
||||||
|
continue
|
||||||
|
case 'A' <= ch && ch <= 'Z':
|
||||||
|
continue
|
||||||
|
case 'a' <= ch && ch <= 'z':
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAny reports whether sv is a google.protobuf.Any message
|
||||||
|
func isAny(sv reflect.Value) bool {
|
||||||
|
type wkt interface {
|
||||||
|
XXX_WellKnownType() string
|
||||||
|
}
|
||||||
|
t, ok := sv.Addr().Interface().(wkt)
|
||||||
|
return ok && t.XXX_WellKnownType() == "Any"
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeProto3Any writes an expanded google.protobuf.Any message.
|
||||||
|
//
|
||||||
|
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
|
||||||
|
// required messages are not linked in).
|
||||||
|
//
|
||||||
|
// It returns (true, error) when sv was written in expanded format or an error
|
||||||
|
// was encountered.
|
||||||
|
func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) {
|
||||||
|
turl := sv.FieldByName("TypeUrl")
|
||||||
|
val := sv.FieldByName("Value")
|
||||||
|
if !turl.IsValid() || !val.IsValid() {
|
||||||
|
return true, errors.New("proto: invalid google.protobuf.Any message")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, ok := val.Interface().([]byte)
|
||||||
|
if !ok {
|
||||||
|
return true, errors.New("proto: invalid google.protobuf.Any message")
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(turl.String(), "/")
|
||||||
|
mt := MessageType(parts[len(parts)-1])
|
||||||
|
if mt == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
m := reflect.New(mt.Elem())
|
||||||
|
if err := Unmarshal(b, m.Interface().(Message)); err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
w.Write([]byte("["))
|
||||||
|
u := turl.String()
|
||||||
|
if requiresQuotes(u) {
|
||||||
|
writeString(w, u)
|
||||||
|
} else {
|
||||||
|
w.Write([]byte(u))
|
||||||
|
}
|
||||||
|
if w.compact {
|
||||||
|
w.Write([]byte("]:<"))
|
||||||
|
} else {
|
||||||
|
w.Write([]byte("]: <\n"))
|
||||||
|
w.ind++
|
||||||
|
}
|
||||||
|
if err := tm.writeStruct(w, m.Elem()); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
if w.compact {
|
||||||
|
w.Write([]byte("> "))
|
||||||
|
} else {
|
||||||
|
w.ind--
|
||||||
|
w.Write([]byte(">\n"))
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
|
if tm.ExpandAny && isAny(sv) {
|
||||||
|
if canExpand, err := tm.writeProto3Any(w, sv); canExpand {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st := sv.Type()
|
||||||
|
sprops := GetProperties(st)
|
||||||
|
for i := 0; i < sv.NumField(); i++ {
|
||||||
|
fv := sv.Field(i)
|
||||||
|
props := sprops.Prop[i]
|
||||||
|
name := st.Field(i).Name
|
||||||
|
|
||||||
|
if strings.HasPrefix(name, "XXX_") {
|
||||||
|
// There are two XXX_ fields:
|
||||||
|
// XXX_unrecognized []byte
|
||||||
|
// XXX_extensions map[int32]proto.Extension
|
||||||
|
// The first is handled here;
|
||||||
|
// the second is handled at the bottom of this function.
|
||||||
|
if name == "XXX_unrecognized" && !fv.IsNil() {
|
||||||
|
if err := writeUnknownStruct(w, fv.Interface().([]byte)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fv.Kind() == reflect.Ptr && fv.IsNil() {
|
||||||
|
// Field not filled in. This could be an optional field or
|
||||||
|
// a required field that wasn't filled in. Either way, there
|
||||||
|
// isn't anything we can show for it.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fv.Kind() == reflect.Slice && fv.IsNil() {
|
||||||
|
// Repeated field that is empty, or a bytes field that is unused.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if props.Repeated && fv.Kind() == reflect.Slice {
|
||||||
|
// Repeated field.
|
||||||
|
for j := 0; j < fv.Len(); j++ {
|
||||||
|
if err := writeName(w, props); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v := fv.Index(j)
|
||||||
|
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||||
|
// A nil message in a repeated field is not valid,
|
||||||
|
// but we can handle that more gracefully than panicking.
|
||||||
|
if _, err := w.Write([]byte("<nil>\n")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := tm.writeAny(w, v, props); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fv.Kind() == reflect.Map {
|
||||||
|
// Map fields are rendered as a repeated struct with key/value fields.
|
||||||
|
keys := fv.MapKeys()
|
||||||
|
sort.Sort(mapKeys(keys))
|
||||||
|
for _, key := range keys {
|
||||||
|
val := fv.MapIndex(key)
|
||||||
|
if err := writeName(w, props); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// open struct
|
||||||
|
if err := w.WriteByte('<'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.indent()
|
||||||
|
// key
|
||||||
|
if _, err := w.WriteString("key:"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := tm.writeAny(w, key, props.mkeyprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// nil values aren't legal, but we can avoid panicking because of them.
|
||||||
|
if val.Kind() != reflect.Ptr || !val.IsNil() {
|
||||||
|
// value
|
||||||
|
if _, err := w.WriteString("value:"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := tm.writeAny(w, val, props.mvalprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// close struct
|
||||||
|
w.unindent()
|
||||||
|
if err := w.WriteByte('>'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if props.proto3 && fv.Kind() == reflect.Slice && fv.Len() == 0 {
|
||||||
|
// empty bytes field
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice {
|
||||||
|
// proto3 non-repeated scalar field; skip if zero value
|
||||||
|
if isProto3Zero(fv) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fv.Kind() == reflect.Interface {
|
||||||
|
// Check if it is a oneof.
|
||||||
|
if st.Field(i).Tag.Get("protobuf_oneof") != "" {
|
||||||
|
// fv is nil, or holds a pointer to generated struct.
|
||||||
|
// That generated struct has exactly one field,
|
||||||
|
// which has a protobuf struct tag.
|
||||||
|
if fv.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
inner := fv.Elem().Elem() // interface -> *T -> T
|
||||||
|
tag := inner.Type().Field(0).Tag.Get("protobuf")
|
||||||
|
props = new(Properties) // Overwrite the outer props var, but not its pointee.
|
||||||
|
props.Parse(tag)
|
||||||
|
// Write the value in the oneof, not the oneof itself.
|
||||||
|
fv = inner.Field(0)
|
||||||
|
|
||||||
|
// Special case to cope with malformed messages gracefully:
|
||||||
|
// If the value in the oneof is a nil pointer, don't panic
|
||||||
|
// in writeAny.
|
||||||
|
if fv.Kind() == reflect.Ptr && fv.IsNil() {
|
||||||
|
// Use errors.New so writeAny won't render quotes.
|
||||||
|
msg := errors.New("/* nil */")
|
||||||
|
fv = reflect.ValueOf(&msg).Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeName(w, props); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if b, ok := fv.Interface().(raw); ok {
|
||||||
|
if err := writeRaw(w, b.Bytes()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enums have a String method, so writeAny will work fine.
|
||||||
|
if err := tm.writeAny(w, fv, props); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extensions (the XXX_extensions field).
|
||||||
|
pv := sv.Addr()
|
||||||
|
if _, ok := extendable(pv.Interface()); ok {
|
||||||
|
if err := tm.writeExtensions(w, pv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeRaw writes an uninterpreted raw message.
|
||||||
|
func writeRaw(w *textWriter, b []byte) error {
|
||||||
|
if err := w.WriteByte('<'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.indent()
|
||||||
|
if err := writeUnknownStruct(w, b); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.unindent()
|
||||||
|
if err := w.WriteByte('>'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeAny writes an arbitrary field.
|
||||||
|
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||||
|
v = reflect.Indirect(v)
|
||||||
|
|
||||||
|
// Floats have special cases.
|
||||||
|
if v.Kind() == reflect.Float32 || v.Kind() == reflect.Float64 {
|
||||||
|
x := v.Float()
|
||||||
|
var b []byte
|
||||||
|
switch {
|
||||||
|
case math.IsInf(x, 1):
|
||||||
|
b = posInf
|
||||||
|
case math.IsInf(x, -1):
|
||||||
|
b = negInf
|
||||||
|
case math.IsNaN(x):
|
||||||
|
b = nan
|
||||||
|
}
|
||||||
|
if b != nil {
|
||||||
|
_, err := w.Write(b)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Other values are handled below.
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't attempt to serialise every possible value type; only those
|
||||||
|
// that can occur in protocol buffers.
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
// Should only be a []byte; repeated fields are handled in writeStruct.
|
||||||
|
if err := writeString(w, string(v.Bytes())); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
if err := writeString(w, v.String()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
// Required/optional group/message.
|
||||||
|
var bra, ket byte = '<', '>'
|
||||||
|
if props != nil && props.Wire == "group" {
|
||||||
|
bra, ket = '{', '}'
|
||||||
|
}
|
||||||
|
if err := w.WriteByte(bra); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.indent()
|
||||||
|
if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||||
|
text, err := etm.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = w.Write(text); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err := tm.writeStruct(w, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.unindent()
|
||||||
|
if err := w.WriteByte(ket); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
_, err := fmt.Fprint(w, v.Interface())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// equivalent to C's isprint.
|
||||||
|
func isprint(c byte) bool {
|
||||||
|
return c >= 0x20 && c < 0x7f
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeString writes a string in the protocol buffer text format.
|
||||||
|
// It is similar to strconv.Quote except we don't use Go escape sequences,
|
||||||
|
// we treat the string as a byte sequence, and we use octal escapes.
|
||||||
|
// These differences are to maintain interoperability with the other
|
||||||
|
// languages' implementations of the text format.
|
||||||
|
func writeString(w *textWriter, s string) error {
|
||||||
|
// use WriteByte here to get any needed indent
|
||||||
|
if err := w.WriteByte('"'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Loop over the bytes, not the runes.
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
var err error
|
||||||
|
// Divergence from C++: we don't escape apostrophes.
|
||||||
|
// There's no need to escape them, and the C++ parser
|
||||||
|
// copes with a naked apostrophe.
|
||||||
|
switch c := s[i]; c {
|
||||||
|
case '\n':
|
||||||
|
_, err = w.w.Write(backslashN)
|
||||||
|
case '\r':
|
||||||
|
_, err = w.w.Write(backslashR)
|
||||||
|
case '\t':
|
||||||
|
_, err = w.w.Write(backslashT)
|
||||||
|
case '"':
|
||||||
|
_, err = w.w.Write(backslashDQ)
|
||||||
|
case '\\':
|
||||||
|
_, err = w.w.Write(backslashBS)
|
||||||
|
default:
|
||||||
|
if isprint(c) {
|
||||||
|
err = w.w.WriteByte(c)
|
||||||
|
} else {
|
||||||
|
_, err = fmt.Fprintf(w.w, "\\%03o", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return w.WriteByte('"')
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
|
||||||
|
if !w.compact {
|
||||||
|
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b := NewBuffer(data)
|
||||||
|
for b.index < len(b.buf) {
|
||||||
|
x, err := b.DecodeVarint()
|
||||||
|
if err != nil {
|
||||||
|
_, err := fmt.Fprintf(w, "/* %v */\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
wire, tag := x&7, x>>3
|
||||||
|
if wire == WireEndGroup {
|
||||||
|
w.unindent()
|
||||||
|
if _, err := w.Write(endBraceNewline); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err := fmt.Fprint(w, tag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if wire != WireStartGroup {
|
||||||
|
if err := w.WriteByte(':'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !w.compact || wire == WireStartGroup {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch wire {
|
||||||
|
case WireBytes:
|
||||||
|
buf, e := b.DecodeRawBytes(false)
|
||||||
|
if e == nil {
|
||||||
|
_, err = fmt.Fprintf(w, "%q", buf)
|
||||||
|
} else {
|
||||||
|
_, err = fmt.Fprintf(w, "/* %v */", e)
|
||||||
|
}
|
||||||
|
case WireFixed32:
|
||||||
|
x, err = b.DecodeFixed32()
|
||||||
|
err = writeUnknownInt(w, x, err)
|
||||||
|
case WireFixed64:
|
||||||
|
x, err = b.DecodeFixed64()
|
||||||
|
err = writeUnknownInt(w, x, err)
|
||||||
|
case WireStartGroup:
|
||||||
|
err = w.WriteByte('{')
|
||||||
|
w.indent()
|
||||||
|
case WireVarint:
|
||||||
|
x, err = b.DecodeVarint()
|
||||||
|
err = writeUnknownInt(w, x, err)
|
||||||
|
default:
|
||||||
|
_, err = fmt.Fprintf(w, "/* unknown wire type %d */", wire)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeUnknownInt(w *textWriter, x uint64, err error) error {
|
||||||
|
if err == nil {
|
||||||
|
_, err = fmt.Fprint(w, x)
|
||||||
|
} else {
|
||||||
|
_, err = fmt.Fprintf(w, "/* %v */", err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type int32Slice []int32
|
||||||
|
|
||||||
|
func (s int32Slice) Len() int { return len(s) }
|
||||||
|
func (s int32Slice) Less(i, j int) bool { return s[i] < s[j] }
|
||||||
|
func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
|
// writeExtensions writes all the extensions in pv.
|
||||||
|
// pv is assumed to be a pointer to a protocol message struct that is extendable.
|
||||||
|
func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||||
|
emap := extensionMaps[pv.Type().Elem()]
|
||||||
|
ep, _ := extendable(pv.Interface())
|
||||||
|
|
||||||
|
// Order the extensions by ID.
|
||||||
|
// This isn't strictly necessary, but it will give us
|
||||||
|
// canonical output, which will also make testing easier.
|
||||||
|
m, mu := ep.extensionsRead()
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
ids := make([]int32, 0, len(m))
|
||||||
|
for id := range m {
|
||||||
|
ids = append(ids, id)
|
||||||
|
}
|
||||||
|
sort.Sort(int32Slice(ids))
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
for _, extNum := range ids {
|
||||||
|
ext := m[extNum]
|
||||||
|
var desc *ExtensionDesc
|
||||||
|
if emap != nil {
|
||||||
|
desc = emap[extNum]
|
||||||
|
}
|
||||||
|
if desc == nil {
|
||||||
|
// Unknown extension.
|
||||||
|
if err := writeUnknownStruct(w, ext.enc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pb, err := GetExtension(ep, desc)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed getting extension: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repeated extensions will appear as a slice.
|
||||||
|
if !desc.repeated() {
|
||||||
|
if err := tm.writeExtension(w, desc.Name, pb); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v := reflect.ValueOf(pb)
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error {
|
||||||
|
if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !w.compact {
|
||||||
|
if err := w.WriteByte(' '); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *textWriter) writeIndent() {
|
||||||
|
if !w.complete {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
remain := w.ind * 2
|
||||||
|
for remain > 0 {
|
||||||
|
n := remain
|
||||||
|
if n > len(spaces) {
|
||||||
|
n = len(spaces)
|
||||||
|
}
|
||||||
|
w.w.Write(spaces[:n])
|
||||||
|
remain -= n
|
||||||
|
}
|
||||||
|
w.complete = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextMarshaler is a configurable text format marshaler.
|
||||||
|
type TextMarshaler struct {
|
||||||
|
Compact bool // use compact text format (one line).
|
||||||
|
ExpandAny bool // expand google.protobuf.Any messages of known types
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal writes a given protocol buffer in text format.
|
||||||
|
// The only errors returned are from w.
|
||||||
|
func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error {
|
||||||
|
val := reflect.ValueOf(pb)
|
||||||
|
if pb == nil || val.IsNil() {
|
||||||
|
w.Write([]byte("<nil>"))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var bw *bufio.Writer
|
||||||
|
ww, ok := w.(writer)
|
||||||
|
if !ok {
|
||||||
|
bw = bufio.NewWriter(w)
|
||||||
|
ww = bw
|
||||||
|
}
|
||||||
|
aw := &textWriter{
|
||||||
|
w: ww,
|
||||||
|
complete: true,
|
||||||
|
compact: tm.Compact,
|
||||||
|
}
|
||||||
|
|
||||||
|
if etm, ok := pb.(encoding.TextMarshaler); ok {
|
||||||
|
text, err := etm.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err = aw.Write(text); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bw != nil {
|
||||||
|
return bw.Flush()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Dereference the received pointer so we don't have outer < and >.
|
||||||
|
v := reflect.Indirect(val)
|
||||||
|
if err := tm.writeStruct(aw, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bw != nil {
|
||||||
|
return bw.Flush()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text is the same as Marshal, but returns the string directly.
|
||||||
|
func (tm *TextMarshaler) Text(pb Message) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
tm.Marshal(&buf, pb)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultTextMarshaler = TextMarshaler{}
|
||||||
|
compactTextMarshaler = TextMarshaler{Compact: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: consider removing some of the Marshal functions below.
|
||||||
|
|
||||||
|
// MarshalText writes a given protocol buffer in text format.
|
||||||
|
// The only errors returned are from w.
|
||||||
|
func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }
|
||||||
|
|
||||||
|
// MarshalTextString is the same as MarshalText, but returns the string directly.
|
||||||
|
func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }
|
||||||
|
|
||||||
|
// CompactText writes a given protocol buffer in compact text format (one line).
|
||||||
|
func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }
|
||||||
|
|
||||||
|
// CompactTextString is the same as CompactText, but returns the string directly.
|
||||||
|
func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }
|
895
vendor/github.com/golang/protobuf/proto/text_parser.go
generated
vendored
Normal file
895
vendor/github.com/golang/protobuf/proto/text_parser.go
generated
vendored
Normal file
|
@ -0,0 +1,895 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package proto
|
||||||
|
|
||||||
|
// Functions for parsing the Text protocol buffer format.
|
||||||
|
// TODO: message sets.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error string emitted when deserializing Any and fields are already set
|
||||||
|
const anyRepeatedlyUnpacked = "Any message unpacked multiple times, or %q already set"
|
||||||
|
|
||||||
|
type ParseError struct {
|
||||||
|
Message string
|
||||||
|
Line int // 1-based line number
|
||||||
|
Offset int // 0-based byte offset from start of input
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ParseError) Error() string {
|
||||||
|
if p.Line == 1 {
|
||||||
|
// show offset only for first line
|
||||||
|
return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("line %d: %v", p.Line, p.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
type token struct {
|
||||||
|
value string
|
||||||
|
err *ParseError
|
||||||
|
line int // line number
|
||||||
|
offset int // byte number from start of input, not start of line
|
||||||
|
unquoted string // the unquoted version of value, if it was a quoted string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *token) String() string {
|
||||||
|
if t.err == nil {
|
||||||
|
return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("parse error: %v", t.err)
|
||||||
|
}
|
||||||
|
|
||||||
|
type textParser struct {
|
||||||
|
s string // remaining input
|
||||||
|
done bool // whether the parsing is finished (success or error)
|
||||||
|
backed bool // whether back() was called
|
||||||
|
offset, line int
|
||||||
|
cur token
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTextParser(s string) *textParser {
|
||||||
|
p := new(textParser)
|
||||||
|
p.s = s
|
||||||
|
p.line = 1
|
||||||
|
p.cur.line = 1
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textParser) errorf(format string, a ...interface{}) *ParseError {
|
||||||
|
pe := &ParseError{fmt.Sprintf(format, a...), p.cur.line, p.cur.offset}
|
||||||
|
p.cur.err = pe
|
||||||
|
p.done = true
|
||||||
|
return pe
|
||||||
|
}
|
||||||
|
|
||||||
|
// Numbers and identifiers are matched by [-+._A-Za-z0-9]
|
||||||
|
func isIdentOrNumberChar(c byte) bool {
|
||||||
|
switch {
|
||||||
|
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
|
||||||
|
return true
|
||||||
|
case '0' <= c && c <= '9':
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
switch c {
|
||||||
|
case '-', '+', '.', '_':
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isWhitespace(c byte) bool {
|
||||||
|
switch c {
|
||||||
|
case ' ', '\t', '\n', '\r':
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isQuote(c byte) bool {
|
||||||
|
switch c {
|
||||||
|
case '"', '\'':
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textParser) skipWhitespace() {
|
||||||
|
i := 0
|
||||||
|
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
|
||||||
|
if p.s[i] == '#' {
|
||||||
|
// comment; skip to end of line or input
|
||||||
|
for i < len(p.s) && p.s[i] != '\n' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i == len(p.s) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.s[i] == '\n' {
|
||||||
|
p.line++
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
p.offset += i
|
||||||
|
p.s = p.s[i:len(p.s)]
|
||||||
|
if len(p.s) == 0 {
|
||||||
|
p.done = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textParser) advance() {
|
||||||
|
// Skip whitespace
|
||||||
|
p.skipWhitespace()
|
||||||
|
if p.done {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start of non-whitespace
|
||||||
|
p.cur.err = nil
|
||||||
|
p.cur.offset, p.cur.line = p.offset, p.line
|
||||||
|
p.cur.unquoted = ""
|
||||||
|
switch p.s[0] {
|
||||||
|
case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/':
|
||||||
|
// Single symbol
|
||||||
|
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
|
||||||
|
case '"', '\'':
|
||||||
|
// Quoted string
|
||||||
|
i := 1
|
||||||
|
for i < len(p.s) && p.s[i] != p.s[0] && p.s[i] != '\n' {
|
||||||
|
if p.s[i] == '\\' && i+1 < len(p.s) {
|
||||||
|
// skip escaped char
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i >= len(p.s) || p.s[i] != p.s[0] {
|
||||||
|
p.errorf("unmatched quote")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
|
||||||
|
if err != nil {
|
||||||
|
p.errorf("invalid quoted string %s: %v", p.s[0:i+1], err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
|
||||||
|
p.cur.unquoted = unq
|
||||||
|
default:
|
||||||
|
i := 0
|
||||||
|
for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i == 0 {
|
||||||
|
p.errorf("unexpected byte %#x", p.s[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
|
||||||
|
}
|
||||||
|
p.offset += len(p.cur.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errBadUTF8 = errors.New("proto: bad UTF-8")
|
||||||
|
errBadHex = errors.New("proto: bad hexadecimal")
|
||||||
|
)
|
||||||
|
|
||||||
|
func unquoteC(s string, quote rune) (string, error) {
|
||||||
|
// This is based on C++'s tokenizer.cc.
|
||||||
|
// Despite its name, this is *not* parsing C syntax.
|
||||||
|
// For instance, "\0" is an invalid quoted string.
|
||||||
|
|
||||||
|
// Avoid allocation in trivial cases.
|
||||||
|
simple := true
|
||||||
|
for _, r := range s {
|
||||||
|
if r == '\\' || r == quote {
|
||||||
|
simple = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if simple {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, 0, 3*len(s)/2)
|
||||||
|
for len(s) > 0 {
|
||||||
|
r, n := utf8.DecodeRuneInString(s)
|
||||||
|
if r == utf8.RuneError && n == 1 {
|
||||||
|
return "", errBadUTF8
|
||||||
|
}
|
||||||
|
s = s[n:]
|
||||||
|
if r != '\\' {
|
||||||
|
if r < utf8.RuneSelf {
|
||||||
|
buf = append(buf, byte(r))
|
||||||
|
} else {
|
||||||
|
buf = append(buf, string(r)...)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ch, tail, err := unescape(s)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
buf = append(buf, ch...)
|
||||||
|
s = tail
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unescape(s string) (ch string, tail string, err error) {
|
||||||
|
r, n := utf8.DecodeRuneInString(s)
|
||||||
|
if r == utf8.RuneError && n == 1 {
|
||||||
|
return "", "", errBadUTF8
|
||||||
|
}
|
||||||
|
s = s[n:]
|
||||||
|
switch r {
|
||||||
|
case 'a':
|
||||||
|
return "\a", s, nil
|
||||||
|
case 'b':
|
||||||
|
return "\b", s, nil
|
||||||
|
case 'f':
|
||||||
|
return "\f", s, nil
|
||||||
|
case 'n':
|
||||||
|
return "\n", s, nil
|
||||||
|
case 'r':
|
||||||
|
return "\r", s, nil
|
||||||
|
case 't':
|
||||||
|
return "\t", s, nil
|
||||||
|
case 'v':
|
||||||
|
return "\v", s, nil
|
||||||
|
case '?':
|
||||||
|
return "?", s, nil // trigraph workaround
|
||||||
|
case '\'', '"', '\\':
|
||||||
|
return string(r), s, nil
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7', 'x', 'X':
|
||||||
|
if len(s) < 2 {
|
||||||
|
return "", "", fmt.Errorf(`\%c requires 2 following digits`, r)
|
||||||
|
}
|
||||||
|
base := 8
|
||||||
|
ss := s[:2]
|
||||||
|
s = s[2:]
|
||||||
|
if r == 'x' || r == 'X' {
|
||||||
|
base = 16
|
||||||
|
} else {
|
||||||
|
ss = string(r) + ss
|
||||||
|
}
|
||||||
|
i, err := strconv.ParseUint(ss, base, 8)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
return string([]byte{byte(i)}), s, nil
|
||||||
|
case 'u', 'U':
|
||||||
|
n := 4
|
||||||
|
if r == 'U' {
|
||||||
|
n = 8
|
||||||
|
}
|
||||||
|
if len(s) < n {
|
||||||
|
return "", "", fmt.Errorf(`\%c requires %d digits`, r, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
bs := make([]byte, n/2)
|
||||||
|
for i := 0; i < n; i += 2 {
|
||||||
|
a, ok1 := unhex(s[i])
|
||||||
|
b, ok2 := unhex(s[i+1])
|
||||||
|
if !ok1 || !ok2 {
|
||||||
|
return "", "", errBadHex
|
||||||
|
}
|
||||||
|
bs[i/2] = a<<4 | b
|
||||||
|
}
|
||||||
|
s = s[n:]
|
||||||
|
return string(bs), s, nil
|
||||||
|
}
|
||||||
|
return "", "", fmt.Errorf(`unknown escape \%c`, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapted from src/pkg/strconv/quote.go.
|
||||||
|
func unhex(b byte) (v byte, ok bool) {
|
||||||
|
switch {
|
||||||
|
case '0' <= b && b <= '9':
|
||||||
|
return b - '0', true
|
||||||
|
case 'a' <= b && b <= 'f':
|
||||||
|
return b - 'a' + 10, true
|
||||||
|
case 'A' <= b && b <= 'F':
|
||||||
|
return b - 'A' + 10, true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back off the parser by one token. Can only be done between calls to next().
|
||||||
|
// It makes the next advance() a no-op.
|
||||||
|
func (p *textParser) back() { p.backed = true }
|
||||||
|
|
||||||
|
// Advances the parser and returns the new current token.
|
||||||
|
func (p *textParser) next() *token {
|
||||||
|
if p.backed || p.done {
|
||||||
|
p.backed = false
|
||||||
|
return &p.cur
|
||||||
|
}
|
||||||
|
p.advance()
|
||||||
|
if p.done {
|
||||||
|
p.cur.value = ""
|
||||||
|
} else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
|
||||||
|
// Look for multiple quoted strings separated by whitespace,
|
||||||
|
// and concatenate them.
|
||||||
|
cat := p.cur
|
||||||
|
for {
|
||||||
|
p.skipWhitespace()
|
||||||
|
if p.done || !isQuote(p.s[0]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.advance()
|
||||||
|
if p.cur.err != nil {
|
||||||
|
return &p.cur
|
||||||
|
}
|
||||||
|
cat.value += " " + p.cur.value
|
||||||
|
cat.unquoted += p.cur.unquoted
|
||||||
|
}
|
||||||
|
p.done = false // parser may have seen EOF, but we want to return cat
|
||||||
|
p.cur = cat
|
||||||
|
}
|
||||||
|
return &p.cur
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textParser) consumeToken(s string) error {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value != s {
|
||||||
|
p.back()
|
||||||
|
return p.errorf("expected %q, found %q", s, tok.value)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a RequiredNotSetError indicating which required field was not set.
|
||||||
|
func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSetError {
|
||||||
|
st := sv.Type()
|
||||||
|
sprops := GetProperties(st)
|
||||||
|
for i := 0; i < st.NumField(); i++ {
|
||||||
|
if !isNil(sv.Field(i)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
props := sprops.Prop[i]
|
||||||
|
if props.Required {
|
||||||
|
return &RequiredNotSetError{fmt.Sprintf("%v.%v", st, props.OrigName)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &RequiredNotSetError{fmt.Sprintf("%v.<unknown field name>", st)} // should not happen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the index in the struct for the named field, as well as the parsed tag properties.
|
||||||
|
func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) {
|
||||||
|
i, ok := sprops.decoderOrigNames[name]
|
||||||
|
if ok {
|
||||||
|
return i, sprops.Prop[i], true
|
||||||
|
}
|
||||||
|
return -1, nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume a ':' from the input stream (if the next token is a colon),
|
||||||
|
// returning an error if a colon is needed but not present.
|
||||||
|
func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseError {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value != ":" {
|
||||||
|
// Colon is optional when the field is a group or message.
|
||||||
|
needColon := true
|
||||||
|
switch props.Wire {
|
||||||
|
case "group":
|
||||||
|
needColon = false
|
||||||
|
case "bytes":
|
||||||
|
// A "bytes" field is either a message, a string, or a repeated field;
|
||||||
|
// those three become *T, *string and []T respectively, so we can check for
|
||||||
|
// this field being a pointer to a non-string.
|
||||||
|
if typ.Kind() == reflect.Ptr {
|
||||||
|
// *T or *string
|
||||||
|
if typ.Elem().Kind() == reflect.String {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if typ.Kind() == reflect.Slice {
|
||||||
|
// []T or []*T
|
||||||
|
if typ.Elem().Kind() != reflect.Ptr {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if typ.Kind() == reflect.String {
|
||||||
|
// The proto3 exception is for a string field,
|
||||||
|
// which requires a colon.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
needColon = false
|
||||||
|
}
|
||||||
|
if needColon {
|
||||||
|
return p.errorf("expected ':', found %q", tok.value)
|
||||||
|
}
|
||||||
|
p.back()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||||
|
st := sv.Type()
|
||||||
|
sprops := GetProperties(st)
|
||||||
|
reqCount := sprops.reqCount
|
||||||
|
var reqFieldErr error
|
||||||
|
fieldSet := make(map[string]bool)
|
||||||
|
// A struct is a sequence of "name: value", terminated by one of
|
||||||
|
// '>' or '}', or the end of the input. A name may also be
|
||||||
|
// "[extension]" or "[type/url]".
|
||||||
|
//
|
||||||
|
// The whole struct can also be an expanded Any message, like:
|
||||||
|
// [type/url] < ... struct contents ... >
|
||||||
|
for {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value == terminator {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if tok.value == "[" {
|
||||||
|
// Looks like an extension or an Any.
|
||||||
|
//
|
||||||
|
// TODO: Check whether we need to handle
|
||||||
|
// namespace rooted names (e.g. ".something.Foo").
|
||||||
|
extName, err := p.consumeExtName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s := strings.LastIndex(extName, "/"); s >= 0 {
|
||||||
|
// If it contains a slash, it's an Any type URL.
|
||||||
|
messageName := extName[s+1:]
|
||||||
|
mt := MessageType(messageName)
|
||||||
|
if mt == nil {
|
||||||
|
return p.errorf("unrecognized message %q in google.protobuf.Any", messageName)
|
||||||
|
}
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
// consume an optional colon
|
||||||
|
if tok.value == ":" {
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var terminator string
|
||||||
|
switch tok.value {
|
||||||
|
case "<":
|
||||||
|
terminator = ">"
|
||||||
|
case "{":
|
||||||
|
terminator = "}"
|
||||||
|
default:
|
||||||
|
return p.errorf("expected '{' or '<', found %q", tok.value)
|
||||||
|
}
|
||||||
|
v := reflect.New(mt.Elem())
|
||||||
|
if pe := p.readStruct(v.Elem(), terminator); pe != nil {
|
||||||
|
return pe
|
||||||
|
}
|
||||||
|
b, err := Marshal(v.Interface().(Message))
|
||||||
|
if err != nil {
|
||||||
|
return p.errorf("failed to marshal message of type %q: %v", messageName, err)
|
||||||
|
}
|
||||||
|
if fieldSet["type_url"] {
|
||||||
|
return p.errorf(anyRepeatedlyUnpacked, "type_url")
|
||||||
|
}
|
||||||
|
if fieldSet["value"] {
|
||||||
|
return p.errorf(anyRepeatedlyUnpacked, "value")
|
||||||
|
}
|
||||||
|
sv.FieldByName("TypeUrl").SetString(extName)
|
||||||
|
sv.FieldByName("Value").SetBytes(b)
|
||||||
|
fieldSet["type_url"] = true
|
||||||
|
fieldSet["value"] = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var desc *ExtensionDesc
|
||||||
|
// This could be faster, but it's functional.
|
||||||
|
// TODO: Do something smarter than a linear scan.
|
||||||
|
for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) {
|
||||||
|
if d.Name == extName {
|
||||||
|
desc = d
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if desc == nil {
|
||||||
|
return p.errorf("unrecognized extension %q", extName)
|
||||||
|
}
|
||||||
|
|
||||||
|
props := &Properties{}
|
||||||
|
props.Parse(desc.Tag)
|
||||||
|
|
||||||
|
typ := reflect.TypeOf(desc.ExtensionType)
|
||||||
|
if err := p.checkForColon(props, typ); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rep := desc.repeated()
|
||||||
|
|
||||||
|
// Read the extension structure, and set it in
|
||||||
|
// the value we're constructing.
|
||||||
|
var ext reflect.Value
|
||||||
|
if !rep {
|
||||||
|
ext = reflect.New(typ).Elem()
|
||||||
|
} else {
|
||||||
|
ext = reflect.New(typ.Elem()).Elem()
|
||||||
|
}
|
||||||
|
if err := p.readAny(ext, props); err != nil {
|
||||||
|
if _, ok := err.(*RequiredNotSetError); !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reqFieldErr = err
|
||||||
|
}
|
||||||
|
ep := sv.Addr().Interface().(Message)
|
||||||
|
if !rep {
|
||||||
|
SetExtension(ep, desc, ext.Interface())
|
||||||
|
} else {
|
||||||
|
old, err := GetExtension(ep, desc)
|
||||||
|
var sl reflect.Value
|
||||||
|
if err == nil {
|
||||||
|
sl = reflect.ValueOf(old) // existing slice
|
||||||
|
} else {
|
||||||
|
sl = reflect.MakeSlice(typ, 0, 1)
|
||||||
|
}
|
||||||
|
sl = reflect.Append(sl, ext)
|
||||||
|
SetExtension(ep, desc, sl.Interface())
|
||||||
|
}
|
||||||
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a normal, non-extension field.
|
||||||
|
name := tok.value
|
||||||
|
var dst reflect.Value
|
||||||
|
fi, props, ok := structFieldByName(sprops, name)
|
||||||
|
if ok {
|
||||||
|
dst = sv.Field(fi)
|
||||||
|
} else if oop, ok := sprops.OneofTypes[name]; ok {
|
||||||
|
// It is a oneof.
|
||||||
|
props = oop.Prop
|
||||||
|
nv := reflect.New(oop.Type.Elem())
|
||||||
|
dst = nv.Elem().Field(0)
|
||||||
|
field := sv.Field(oop.Field)
|
||||||
|
if !field.IsNil() {
|
||||||
|
return p.errorf("field '%s' would overwrite already parsed oneof '%s'", name, sv.Type().Field(oop.Field).Name)
|
||||||
|
}
|
||||||
|
field.Set(nv)
|
||||||
|
}
|
||||||
|
if !dst.IsValid() {
|
||||||
|
return p.errorf("unknown field name %q in %v", name, st)
|
||||||
|
}
|
||||||
|
|
||||||
|
if dst.Kind() == reflect.Map {
|
||||||
|
// Consume any colon.
|
||||||
|
if err := p.checkForColon(props, dst.Type()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the map if it doesn't already exist.
|
||||||
|
if dst.IsNil() {
|
||||||
|
dst.Set(reflect.MakeMap(dst.Type()))
|
||||||
|
}
|
||||||
|
key := reflect.New(dst.Type().Key()).Elem()
|
||||||
|
val := reflect.New(dst.Type().Elem()).Elem()
|
||||||
|
|
||||||
|
// The map entry should be this sequence of tokens:
|
||||||
|
// < key : KEY value : VALUE >
|
||||||
|
// However, implementations may omit key or value, and technically
|
||||||
|
// we should support them in any order. See b/28924776 for a time
|
||||||
|
// this went wrong.
|
||||||
|
|
||||||
|
tok := p.next()
|
||||||
|
var terminator string
|
||||||
|
switch tok.value {
|
||||||
|
case "<":
|
||||||
|
terminator = ">"
|
||||||
|
case "{":
|
||||||
|
terminator = "}"
|
||||||
|
default:
|
||||||
|
return p.errorf("expected '{' or '<', found %q", tok.value)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value == terminator {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch tok.value {
|
||||||
|
case "key":
|
||||||
|
if err := p.consumeToken(":"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.readAny(key, props.mkeyprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "value":
|
||||||
|
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.readAny(val, props.mvalprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
p.back()
|
||||||
|
return p.errorf(`expected "key", "value", or %q, found %q`, terminator, tok.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.SetMapIndex(key, val)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that it's not already set if it's not a repeated field.
|
||||||
|
if !props.Repeated && fieldSet[name] {
|
||||||
|
return p.errorf("non-repeated field %q was repeated", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.checkForColon(props, dst.Type()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse into the field.
|
||||||
|
fieldSet[name] = true
|
||||||
|
if err := p.readAny(dst, props); err != nil {
|
||||||
|
if _, ok := err.(*RequiredNotSetError); !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reqFieldErr = err
|
||||||
|
}
|
||||||
|
if props.Required {
|
||||||
|
reqCount--
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqCount > 0 {
|
||||||
|
return p.missingRequiredFieldError(sv)
|
||||||
|
}
|
||||||
|
return reqFieldErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// consumeExtName consumes extension name or expanded Any type URL and the
|
||||||
|
// following ']'. It returns the name or URL consumed.
|
||||||
|
func (p *textParser) consumeExtName() (string, error) {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return "", tok.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If extension name or type url is quoted, it's a single token.
|
||||||
|
if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] {
|
||||||
|
name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0]))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return name, p.consumeToken("]")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume everything up to "]"
|
||||||
|
var parts []string
|
||||||
|
for tok.value != "]" {
|
||||||
|
parts = append(parts, tok.value)
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(parts, ""), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// consumeOptionalSeparator consumes an optional semicolon or comma.
|
||||||
|
// It is used in readStruct to provide backward compatibility.
|
||||||
|
func (p *textParser) consumeOptionalSeparator() error {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value != ";" && tok.value != "," {
|
||||||
|
p.back()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *textParser) readAny(v reflect.Value, props *Properties) error {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value == "" {
|
||||||
|
return p.errorf("unexpected EOF")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fv := v; fv.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
at := v.Type()
|
||||||
|
if at.Elem().Kind() == reflect.Uint8 {
|
||||||
|
// Special case for []byte
|
||||||
|
if tok.value[0] != '"' && tok.value[0] != '\'' {
|
||||||
|
// Deliberately written out here, as the error after
|
||||||
|
// this switch statement would write "invalid []byte: ...",
|
||||||
|
// which is not as user-friendly.
|
||||||
|
return p.errorf("invalid string: %v", tok.value)
|
||||||
|
}
|
||||||
|
bytes := []byte(tok.unquoted)
|
||||||
|
fv.Set(reflect.ValueOf(bytes))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Repeated field.
|
||||||
|
if tok.value == "[" {
|
||||||
|
// Repeated field with list notation, like [1,2,3].
|
||||||
|
for {
|
||||||
|
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem()))
|
||||||
|
err := p.readAny(fv.Index(fv.Len()-1), props)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value == "]" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if tok.value != "," {
|
||||||
|
return p.errorf("Expected ']' or ',' found %q", tok.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// One value of the repeated field.
|
||||||
|
p.back()
|
||||||
|
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem()))
|
||||||
|
return p.readAny(fv.Index(fv.Len()-1), props)
|
||||||
|
case reflect.Bool:
|
||||||
|
// true/1/t/True or false/f/0/False.
|
||||||
|
switch tok.value {
|
||||||
|
case "true", "1", "t", "True":
|
||||||
|
fv.SetBool(true)
|
||||||
|
return nil
|
||||||
|
case "false", "0", "f", "False":
|
||||||
|
fv.SetBool(false)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
v := tok.value
|
||||||
|
// Ignore 'f' for compatibility with output generated by C++, but don't
|
||||||
|
// remove 'f' when the value is "-inf" or "inf".
|
||||||
|
if strings.HasSuffix(v, "f") && tok.value != "-inf" && tok.value != "inf" {
|
||||||
|
v = v[:len(v)-1]
|
||||||
|
}
|
||||||
|
if f, err := strconv.ParseFloat(v, fv.Type().Bits()); err == nil {
|
||||||
|
fv.SetFloat(f)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case reflect.Int32:
|
||||||
|
if x, err := strconv.ParseInt(tok.value, 0, 32); err == nil {
|
||||||
|
fv.SetInt(x)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(props.Enum) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
m, ok := enumValueMaps[props.Enum]
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x, ok := m[tok.value]
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fv.SetInt(int64(x))
|
||||||
|
return nil
|
||||||
|
case reflect.Int64:
|
||||||
|
if x, err := strconv.ParseInt(tok.value, 0, 64); err == nil {
|
||||||
|
fv.SetInt(x)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
case reflect.Ptr:
|
||||||
|
// A basic field (indirected through pointer), or a repeated message/group
|
||||||
|
p.back()
|
||||||
|
fv.Set(reflect.New(fv.Type().Elem()))
|
||||||
|
return p.readAny(fv.Elem(), props)
|
||||||
|
case reflect.String:
|
||||||
|
if tok.value[0] == '"' || tok.value[0] == '\'' {
|
||||||
|
fv.SetString(tok.unquoted)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
var terminator string
|
||||||
|
switch tok.value {
|
||||||
|
case "{":
|
||||||
|
terminator = "}"
|
||||||
|
case "<":
|
||||||
|
terminator = ">"
|
||||||
|
default:
|
||||||
|
return p.errorf("expected '{' or '<', found %q", tok.value)
|
||||||
|
}
|
||||||
|
// TODO: Handle nested messages which implement encoding.TextUnmarshaler.
|
||||||
|
return p.readStruct(fv, terminator)
|
||||||
|
case reflect.Uint32:
|
||||||
|
if x, err := strconv.ParseUint(tok.value, 0, 32); err == nil {
|
||||||
|
fv.SetUint(x)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case reflect.Uint64:
|
||||||
|
if x, err := strconv.ParseUint(tok.value, 0, 64); err == nil {
|
||||||
|
fv.SetUint(x)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p.errorf("invalid %v: %v", v.Type(), tok.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText reads a protocol buffer in Text format. UnmarshalText resets pb
|
||||||
|
// before starting to unmarshal, so any existing data in pb is always removed.
|
||||||
|
// If a required field is not set and no other error occurs,
|
||||||
|
// UnmarshalText returns *RequiredNotSetError.
|
||||||
|
func UnmarshalText(s string, pb Message) error {
|
||||||
|
if um, ok := pb.(encoding.TextUnmarshaler); ok {
|
||||||
|
err := um.UnmarshalText([]byte(s))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pb.Reset()
|
||||||
|
v := reflect.ValueOf(pb)
|
||||||
|
if pe := newTextParser(s).readStruct(v.Elem(), ""); pe != nil {
|
||||||
|
return pe
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
139
vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
Normal file
139
vendor/github.com/golang/protobuf/ptypes/any.go
generated
vendored
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package ptypes
|
||||||
|
|
||||||
|
// This file implements functions to marshal proto.Message to/from
|
||||||
|
// google.protobuf.Any message.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"github.com/golang/protobuf/ptypes/any"
|
||||||
|
)
|
||||||
|
|
||||||
|
const googleApis = "type.googleapis.com/"
|
||||||
|
|
||||||
|
// AnyMessageName returns the name of the message contained in a google.protobuf.Any message.
|
||||||
|
//
|
||||||
|
// Note that regular type assertions should be done using the Is
|
||||||
|
// function. AnyMessageName is provided for less common use cases like filtering a
|
||||||
|
// sequence of Any messages based on a set of allowed message type names.
|
||||||
|
func AnyMessageName(any *any.Any) (string, error) {
|
||||||
|
if any == nil {
|
||||||
|
return "", fmt.Errorf("message is nil")
|
||||||
|
}
|
||||||
|
slash := strings.LastIndex(any.TypeUrl, "/")
|
||||||
|
if slash < 0 {
|
||||||
|
return "", fmt.Errorf("message type url %q is invalid", any.TypeUrl)
|
||||||
|
}
|
||||||
|
return any.TypeUrl[slash+1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalAny takes the protocol buffer and encodes it into google.protobuf.Any.
|
||||||
|
func MarshalAny(pb proto.Message) (*any.Any, error) {
|
||||||
|
value, err := proto.Marshal(pb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &any.Any{TypeUrl: googleApis + proto.MessageName(pb), Value: value}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DynamicAny is a value that can be passed to UnmarshalAny to automatically
|
||||||
|
// allocate a proto.Message for the type specified in a google.protobuf.Any
|
||||||
|
// message. The allocated message is stored in the embedded proto.Message.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// var x ptypes.DynamicAny
|
||||||
|
// if err := ptypes.UnmarshalAny(a, &x); err != nil { ... }
|
||||||
|
// fmt.Printf("unmarshaled message: %v", x.Message)
|
||||||
|
type DynamicAny struct {
|
||||||
|
proto.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty returns a new proto.Message of the type specified in a
|
||||||
|
// google.protobuf.Any message. It returns an error if corresponding message
|
||||||
|
// type isn't linked in.
|
||||||
|
func Empty(any *any.Any) (proto.Message, error) {
|
||||||
|
aname, err := AnyMessageName(any)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := proto.MessageType(aname)
|
||||||
|
if t == nil {
|
||||||
|
return nil, fmt.Errorf("any: message type %q isn't linked in", aname)
|
||||||
|
}
|
||||||
|
return reflect.New(t.Elem()).Interface().(proto.Message), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalAny parses the protocol buffer representation in a google.protobuf.Any
|
||||||
|
// message and places the decoded result in pb. It returns an error if type of
|
||||||
|
// contents of Any message does not match type of pb message.
|
||||||
|
//
|
||||||
|
// pb can be a proto.Message, or a *DynamicAny.
|
||||||
|
func UnmarshalAny(any *any.Any, pb proto.Message) error {
|
||||||
|
if d, ok := pb.(*DynamicAny); ok {
|
||||||
|
if d.Message == nil {
|
||||||
|
var err error
|
||||||
|
d.Message, err = Empty(any)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UnmarshalAny(any, d.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
aname, err := AnyMessageName(any)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mname := proto.MessageName(pb)
|
||||||
|
if aname != mname {
|
||||||
|
return fmt.Errorf("mismatched message type: got %q want %q", aname, mname)
|
||||||
|
}
|
||||||
|
return proto.Unmarshal(any.Value, pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is returns true if any value contains a given message type.
|
||||||
|
func Is(any *any.Any, pb proto.Message) bool {
|
||||||
|
aname, err := AnyMessageName(any)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return aname == proto.MessageName(pb)
|
||||||
|
}
|
178
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
Normal file
178
vendor/github.com/golang/protobuf/ptypes/any/any.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: google/protobuf/any.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package any is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
google/protobuf/any.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Any
|
||||||
|
*/
|
||||||
|
package any
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||||
|
// URL that describes the type of the serialized message.
|
||||||
|
//
|
||||||
|
// Protobuf library provides support to pack/unpack Any values in the form
|
||||||
|
// of utility functions or additional generated methods of the Any type.
|
||||||
|
//
|
||||||
|
// Example 1: Pack and unpack a message in C++.
|
||||||
|
//
|
||||||
|
// Foo foo = ...;
|
||||||
|
// Any any;
|
||||||
|
// any.PackFrom(foo);
|
||||||
|
// ...
|
||||||
|
// if (any.UnpackTo(&foo)) {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 2: Pack and unpack a message in Java.
|
||||||
|
//
|
||||||
|
// Foo foo = ...;
|
||||||
|
// Any any = Any.pack(foo);
|
||||||
|
// ...
|
||||||
|
// if (any.is(Foo.class)) {
|
||||||
|
// foo = any.unpack(Foo.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 3: Pack and unpack a message in Python.
|
||||||
|
//
|
||||||
|
// foo = Foo(...)
|
||||||
|
// any = Any()
|
||||||
|
// any.Pack(foo)
|
||||||
|
// ...
|
||||||
|
// if any.Is(Foo.DESCRIPTOR):
|
||||||
|
// any.Unpack(foo)
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// Example 4: Pack and unpack a message in Go
|
||||||
|
//
|
||||||
|
// foo := &pb.Foo{...}
|
||||||
|
// any, err := ptypes.MarshalAny(foo)
|
||||||
|
// ...
|
||||||
|
// foo := &pb.Foo{}
|
||||||
|
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The pack methods provided by protobuf library will by default use
|
||||||
|
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||||
|
// methods only use the fully qualified type name after the last '/'
|
||||||
|
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||||
|
// name "y.z".
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// JSON
|
||||||
|
// ====
|
||||||
|
// The JSON representation of an `Any` value uses the regular
|
||||||
|
// representation of the deserialized, embedded message, with an
|
||||||
|
// additional field `@type` which contains the type URL. Example:
|
||||||
|
//
|
||||||
|
// package google.profile;
|
||||||
|
// message Person {
|
||||||
|
// string first_name = 1;
|
||||||
|
// string last_name = 2;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "@type": "type.googleapis.com/google.profile.Person",
|
||||||
|
// "firstName": <string>,
|
||||||
|
// "lastName": <string>
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If the embedded message type is well-known and has a custom JSON
|
||||||
|
// representation, that representation will be embedded adding a field
|
||||||
|
// `value` which holds the custom JSON in addition to the `@type`
|
||||||
|
// field. Example (for message [google.protobuf.Duration][]):
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||||
|
// "value": "1.212s"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
type Any struct {
|
||||||
|
// A URL/resource name whose content describes the type of the
|
||||||
|
// serialized protocol buffer message.
|
||||||
|
//
|
||||||
|
// For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||||
|
// following restrictions and interpretations apply:
|
||||||
|
//
|
||||||
|
// * If no scheme is provided, `https` is assumed.
|
||||||
|
// * The last segment of the URL's path must represent the fully
|
||||||
|
// qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||||
|
// The name should be in a canonical form (e.g., leading "." is
|
||||||
|
// not accepted).
|
||||||
|
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||||
|
// value in binary format, or produce an error.
|
||||||
|
// * Applications are allowed to cache lookup results based on the
|
||||||
|
// URL, or have them precompiled into a binary to avoid any
|
||||||
|
// lookup. Therefore, binary compatibility needs to be preserved
|
||||||
|
// on changes to types. (Use versioned type names to manage
|
||||||
|
// breaking changes.)
|
||||||
|
//
|
||||||
|
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||||
|
// used with implementation specific semantics.
|
||||||
|
//
|
||||||
|
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl" json:"type_url,omitempty"`
|
||||||
|
// Must be a valid serialized protocol buffer of the above specified type.
|
||||||
|
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Any) Reset() { *m = Any{} }
|
||||||
|
func (m *Any) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Any) ProtoMessage() {}
|
||||||
|
func (*Any) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
func (*Any) XXX_WellKnownType() string { return "Any" }
|
||||||
|
|
||||||
|
func (m *Any) GetTypeUrl() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.TypeUrl
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Any) GetValue() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Any)(nil), "google.protobuf.Any")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("google/protobuf/any.proto", fileDescriptor0) }
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 185 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4c, 0xcf, 0xcf, 0x4f,
|
||||||
|
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0xcc, 0xab, 0xd4,
|
||||||
|
0x03, 0x73, 0x84, 0xf8, 0x21, 0x52, 0x7a, 0x30, 0x29, 0x25, 0x33, 0x2e, 0x66, 0xc7, 0xbc, 0x4a,
|
||||||
|
0x21, 0x49, 0x2e, 0x8e, 0x92, 0xca, 0x82, 0xd4, 0xf8, 0xd2, 0xa2, 0x1c, 0x09, 0x46, 0x05, 0x46,
|
||||||
|
0x0d, 0xce, 0x20, 0x76, 0x10, 0x3f, 0xb4, 0x28, 0x47, 0x48, 0x84, 0x8b, 0xb5, 0x2c, 0x31, 0xa7,
|
||||||
|
0x34, 0x55, 0x82, 0x49, 0x81, 0x51, 0x83, 0x27, 0x08, 0xc2, 0x71, 0xca, 0xe7, 0x12, 0x4e, 0xce,
|
||||||
|
0xcf, 0xd5, 0x43, 0x33, 0xce, 0x89, 0xc3, 0x31, 0xaf, 0x32, 0x00, 0xc4, 0x09, 0x60, 0x8c, 0x52,
|
||||||
|
0x4d, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc,
|
||||||
|
0x4b, 0x47, 0xb8, 0xa8, 0x00, 0x64, 0x7a, 0x31, 0xc8, 0x61, 0x8b, 0x98, 0x98, 0xdd, 0x03, 0x9c,
|
||||||
|
0x56, 0x31, 0xc9, 0xb9, 0x43, 0x8c, 0x0a, 0x80, 0x2a, 0xd1, 0x0b, 0x4f, 0xcd, 0xc9, 0xf1, 0xce,
|
||||||
|
0xcb, 0x2f, 0xcf, 0x0b, 0x01, 0x29, 0x4d, 0x62, 0x03, 0xeb, 0x35, 0x06, 0x04, 0x00, 0x00, 0xff,
|
||||||
|
0xff, 0x13, 0xf8, 0xe8, 0x42, 0xdd, 0x00, 0x00, 0x00,
|
||||||
|
}
|
149
vendor/github.com/golang/protobuf/ptypes/any/any.proto
generated
vendored
Normal file
149
vendor/github.com/golang/protobuf/ptypes/any/any.proto
generated
vendored
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package google.protobuf;
|
||||||
|
|
||||||
|
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||||
|
option go_package = "github.com/golang/protobuf/ptypes/any";
|
||||||
|
option java_package = "com.google.protobuf";
|
||||||
|
option java_outer_classname = "AnyProto";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
option objc_class_prefix = "GPB";
|
||||||
|
|
||||||
|
// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||||
|
// URL that describes the type of the serialized message.
|
||||||
|
//
|
||||||
|
// Protobuf library provides support to pack/unpack Any values in the form
|
||||||
|
// of utility functions or additional generated methods of the Any type.
|
||||||
|
//
|
||||||
|
// Example 1: Pack and unpack a message in C++.
|
||||||
|
//
|
||||||
|
// Foo foo = ...;
|
||||||
|
// Any any;
|
||||||
|
// any.PackFrom(foo);
|
||||||
|
// ...
|
||||||
|
// if (any.UnpackTo(&foo)) {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 2: Pack and unpack a message in Java.
|
||||||
|
//
|
||||||
|
// Foo foo = ...;
|
||||||
|
// Any any = Any.pack(foo);
|
||||||
|
// ...
|
||||||
|
// if (any.is(Foo.class)) {
|
||||||
|
// foo = any.unpack(Foo.class);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 3: Pack and unpack a message in Python.
|
||||||
|
//
|
||||||
|
// foo = Foo(...)
|
||||||
|
// any = Any()
|
||||||
|
// any.Pack(foo)
|
||||||
|
// ...
|
||||||
|
// if any.Is(Foo.DESCRIPTOR):
|
||||||
|
// any.Unpack(foo)
|
||||||
|
// ...
|
||||||
|
//
|
||||||
|
// Example 4: Pack and unpack a message in Go
|
||||||
|
//
|
||||||
|
// foo := &pb.Foo{...}
|
||||||
|
// any, err := ptypes.MarshalAny(foo)
|
||||||
|
// ...
|
||||||
|
// foo := &pb.Foo{}
|
||||||
|
// if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
||||||
|
// ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The pack methods provided by protobuf library will by default use
|
||||||
|
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||||
|
// methods only use the fully qualified type name after the last '/'
|
||||||
|
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||||
|
// name "y.z".
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// JSON
|
||||||
|
// ====
|
||||||
|
// The JSON representation of an `Any` value uses the regular
|
||||||
|
// representation of the deserialized, embedded message, with an
|
||||||
|
// additional field `@type` which contains the type URL. Example:
|
||||||
|
//
|
||||||
|
// package google.profile;
|
||||||
|
// message Person {
|
||||||
|
// string first_name = 1;
|
||||||
|
// string last_name = 2;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "@type": "type.googleapis.com/google.profile.Person",
|
||||||
|
// "firstName": <string>,
|
||||||
|
// "lastName": <string>
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If the embedded message type is well-known and has a custom JSON
|
||||||
|
// representation, that representation will be embedded adding a field
|
||||||
|
// `value` which holds the custom JSON in addition to the `@type`
|
||||||
|
// field. Example (for message [google.protobuf.Duration][]):
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||||
|
// "value": "1.212s"
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
message Any {
|
||||||
|
// A URL/resource name whose content describes the type of the
|
||||||
|
// serialized protocol buffer message.
|
||||||
|
//
|
||||||
|
// For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||||
|
// following restrictions and interpretations apply:
|
||||||
|
//
|
||||||
|
// * If no scheme is provided, `https` is assumed.
|
||||||
|
// * The last segment of the URL's path must represent the fully
|
||||||
|
// qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||||
|
// The name should be in a canonical form (e.g., leading "." is
|
||||||
|
// not accepted).
|
||||||
|
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||||
|
// value in binary format, or produce an error.
|
||||||
|
// * Applications are allowed to cache lookup results based on the
|
||||||
|
// URL, or have them precompiled into a binary to avoid any
|
||||||
|
// lookup. Therefore, binary compatibility needs to be preserved
|
||||||
|
// on changes to types. (Use versioned type names to manage
|
||||||
|
// breaking changes.)
|
||||||
|
//
|
||||||
|
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||||
|
// used with implementation specific semantics.
|
||||||
|
//
|
||||||
|
string type_url = 1;
|
||||||
|
|
||||||
|
// Must be a valid serialized protocol buffer of the above specified type.
|
||||||
|
bytes value = 2;
|
||||||
|
}
|
35
vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
Normal file
35
vendor/github.com/golang/protobuf/ptypes/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package ptypes contains code for interacting with well-known types.
|
||||||
|
*/
|
||||||
|
package ptypes
|
102
vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
Normal file
102
vendor/github.com/golang/protobuf/ptypes/duration.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package ptypes
|
||||||
|
|
||||||
|
// This file implements conversions between google.protobuf.Duration
|
||||||
|
// and time.Duration.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
durpb "github.com/golang/protobuf/ptypes/duration"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Range of a durpb.Duration in seconds, as specified in
|
||||||
|
// google/protobuf/duration.proto. This is about 10,000 years in seconds.
|
||||||
|
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
|
||||||
|
minSeconds = -maxSeconds
|
||||||
|
)
|
||||||
|
|
||||||
|
// validateDuration determines whether the durpb.Duration is valid according to the
|
||||||
|
// definition in google/protobuf/duration.proto. A valid durpb.Duration
|
||||||
|
// may still be too large to fit into a time.Duration (the range of durpb.Duration
|
||||||
|
// is about 10,000 years, and the range of time.Duration is about 290).
|
||||||
|
func validateDuration(d *durpb.Duration) error {
|
||||||
|
if d == nil {
|
||||||
|
return errors.New("duration: nil Duration")
|
||||||
|
}
|
||||||
|
if d.Seconds < minSeconds || d.Seconds > maxSeconds {
|
||||||
|
return fmt.Errorf("duration: %v: seconds out of range", d)
|
||||||
|
}
|
||||||
|
if d.Nanos <= -1e9 || d.Nanos >= 1e9 {
|
||||||
|
return fmt.Errorf("duration: %v: nanos out of range", d)
|
||||||
|
}
|
||||||
|
// Seconds and Nanos must have the same sign, unless d.Nanos is zero.
|
||||||
|
if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) {
|
||||||
|
return fmt.Errorf("duration: %v: seconds and nanos have different signs", d)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duration converts a durpb.Duration to a time.Duration. Duration
|
||||||
|
// returns an error if the durpb.Duration is invalid or is too large to be
|
||||||
|
// represented in a time.Duration.
|
||||||
|
func Duration(p *durpb.Duration) (time.Duration, error) {
|
||||||
|
if err := validateDuration(p); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
d := time.Duration(p.Seconds) * time.Second
|
||||||
|
if int64(d/time.Second) != p.Seconds {
|
||||||
|
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
|
||||||
|
}
|
||||||
|
if p.Nanos != 0 {
|
||||||
|
d += time.Duration(p.Nanos)
|
||||||
|
if (d < 0) != (p.Nanos < 0) {
|
||||||
|
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DurationProto converts a time.Duration to a durpb.Duration.
|
||||||
|
func DurationProto(d time.Duration) *durpb.Duration {
|
||||||
|
nanos := d.Nanoseconds()
|
||||||
|
secs := nanos / 1e9
|
||||||
|
nanos -= secs * 1e9
|
||||||
|
return &durpb.Duration{
|
||||||
|
Seconds: secs,
|
||||||
|
Nanos: int32(nanos),
|
||||||
|
}
|
||||||
|
}
|
144
vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
Normal file
144
vendor/github.com/golang/protobuf/ptypes/duration/duration.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: google/protobuf/duration.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package duration is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
google/protobuf/duration.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Duration
|
||||||
|
*/
|
||||||
|
package duration
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// A Duration represents a signed, fixed-length span of time represented
|
||||||
|
// as a count of seconds and fractions of seconds at nanosecond
|
||||||
|
// resolution. It is independent of any calendar and concepts like "day"
|
||||||
|
// or "month". It is related to Timestamp in that the difference between
|
||||||
|
// two Timestamp values is a Duration and it can be added or subtracted
|
||||||
|
// from a Timestamp. Range is approximately +-10,000 years.
|
||||||
|
//
|
||||||
|
// # Examples
|
||||||
|
//
|
||||||
|
// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||||
|
//
|
||||||
|
// Timestamp start = ...;
|
||||||
|
// Timestamp end = ...;
|
||||||
|
// Duration duration = ...;
|
||||||
|
//
|
||||||
|
// duration.seconds = end.seconds - start.seconds;
|
||||||
|
// duration.nanos = end.nanos - start.nanos;
|
||||||
|
//
|
||||||
|
// if (duration.seconds < 0 && duration.nanos > 0) {
|
||||||
|
// duration.seconds += 1;
|
||||||
|
// duration.nanos -= 1000000000;
|
||||||
|
// } else if (durations.seconds > 0 && duration.nanos < 0) {
|
||||||
|
// duration.seconds -= 1;
|
||||||
|
// duration.nanos += 1000000000;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
|
||||||
|
//
|
||||||
|
// Timestamp start = ...;
|
||||||
|
// Duration duration = ...;
|
||||||
|
// Timestamp end = ...;
|
||||||
|
//
|
||||||
|
// end.seconds = start.seconds + duration.seconds;
|
||||||
|
// end.nanos = start.nanos + duration.nanos;
|
||||||
|
//
|
||||||
|
// if (end.nanos < 0) {
|
||||||
|
// end.seconds -= 1;
|
||||||
|
// end.nanos += 1000000000;
|
||||||
|
// } else if (end.nanos >= 1000000000) {
|
||||||
|
// end.seconds += 1;
|
||||||
|
// end.nanos -= 1000000000;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 3: Compute Duration from datetime.timedelta in Python.
|
||||||
|
//
|
||||||
|
// td = datetime.timedelta(days=3, minutes=10)
|
||||||
|
// duration = Duration()
|
||||||
|
// duration.FromTimedelta(td)
|
||||||
|
//
|
||||||
|
// # JSON Mapping
|
||||||
|
//
|
||||||
|
// In JSON format, the Duration type is encoded as a string rather than an
|
||||||
|
// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||||
|
// is preceded by the number of seconds, with nanoseconds expressed as
|
||||||
|
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||||
|
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||||
|
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||||
|
// microsecond should be expressed in JSON format as "3.000001s".
|
||||||
|
//
|
||||||
|
//
|
||||||
|
type Duration struct {
|
||||||
|
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||||
|
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||||
|
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||||
|
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
|
||||||
|
// Signed fractions of a second at nanosecond resolution of the span
|
||||||
|
// of time. Durations less than one second are represented with a 0
|
||||||
|
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||||
|
// of one second or more, a non-zero value for the `nanos` field must be
|
||||||
|
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||||
|
// to +999,999,999 inclusive.
|
||||||
|
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Duration) Reset() { *m = Duration{} }
|
||||||
|
func (m *Duration) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Duration) ProtoMessage() {}
|
||||||
|
func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
func (*Duration) XXX_WellKnownType() string { return "Duration" }
|
||||||
|
|
||||||
|
func (m *Duration) GetSeconds() int64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Seconds
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Duration) GetNanos() int32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Nanos
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Duration)(nil), "google.protobuf.Duration")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("google/protobuf/duration.proto", fileDescriptor0) }
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 190 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xcf, 0xcf, 0x4f,
|
||||||
|
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x4f, 0x29, 0x2d, 0x4a,
|
||||||
|
0x2c, 0xc9, 0xcc, 0xcf, 0xd3, 0x03, 0x8b, 0x08, 0xf1, 0x43, 0xe4, 0xf5, 0x60, 0xf2, 0x4a, 0x56,
|
||||||
|
0x5c, 0x1c, 0x2e, 0x50, 0x25, 0x42, 0x12, 0x5c, 0xec, 0xc5, 0xa9, 0xc9, 0xf9, 0x79, 0x29, 0xc5,
|
||||||
|
0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x30, 0xae, 0x90, 0x08, 0x17, 0x6b, 0x5e, 0x62, 0x5e,
|
||||||
|
0x7e, 0xb1, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x6b, 0x10, 0x84, 0xe3, 0x54, 0xc3, 0x25, 0x9c, 0x9c,
|
||||||
|
0x9f, 0xab, 0x87, 0x66, 0xa4, 0x13, 0x2f, 0xcc, 0xc0, 0x00, 0x90, 0x48, 0x00, 0x63, 0x94, 0x56,
|
||||||
|
0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x7e, 0x7a, 0x7e, 0x4e, 0x62, 0x5e,
|
||||||
|
0x3a, 0xc2, 0x7d, 0x05, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x70, 0x67, 0xfe, 0x60, 0x64, 0x5c, 0xc4,
|
||||||
|
0xc4, 0xec, 0x1e, 0xe0, 0xb4, 0x8a, 0x49, 0xce, 0x1d, 0x62, 0x6e, 0x00, 0x54, 0xa9, 0x5e, 0x78,
|
||||||
|
0x6a, 0x4e, 0x8e, 0x77, 0x5e, 0x7e, 0x79, 0x5e, 0x08, 0x48, 0x4b, 0x12, 0x1b, 0xd8, 0x0c, 0x63,
|
||||||
|
0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, 0x84, 0x30, 0xff, 0xf3, 0x00, 0x00, 0x00,
|
||||||
|
}
|
117
vendor/github.com/golang/protobuf/ptypes/duration/duration.proto
generated
vendored
Normal file
117
vendor/github.com/golang/protobuf/ptypes/duration/duration.proto
generated
vendored
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package google.protobuf;
|
||||||
|
|
||||||
|
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||||
|
option cc_enable_arenas = true;
|
||||||
|
option go_package = "github.com/golang/protobuf/ptypes/duration";
|
||||||
|
option java_package = "com.google.protobuf";
|
||||||
|
option java_outer_classname = "DurationProto";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
option objc_class_prefix = "GPB";
|
||||||
|
|
||||||
|
// A Duration represents a signed, fixed-length span of time represented
|
||||||
|
// as a count of seconds and fractions of seconds at nanosecond
|
||||||
|
// resolution. It is independent of any calendar and concepts like "day"
|
||||||
|
// or "month". It is related to Timestamp in that the difference between
|
||||||
|
// two Timestamp values is a Duration and it can be added or subtracted
|
||||||
|
// from a Timestamp. Range is approximately +-10,000 years.
|
||||||
|
//
|
||||||
|
// # Examples
|
||||||
|
//
|
||||||
|
// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||||
|
//
|
||||||
|
// Timestamp start = ...;
|
||||||
|
// Timestamp end = ...;
|
||||||
|
// Duration duration = ...;
|
||||||
|
//
|
||||||
|
// duration.seconds = end.seconds - start.seconds;
|
||||||
|
// duration.nanos = end.nanos - start.nanos;
|
||||||
|
//
|
||||||
|
// if (duration.seconds < 0 && duration.nanos > 0) {
|
||||||
|
// duration.seconds += 1;
|
||||||
|
// duration.nanos -= 1000000000;
|
||||||
|
// } else if (durations.seconds > 0 && duration.nanos < 0) {
|
||||||
|
// duration.seconds -= 1;
|
||||||
|
// duration.nanos += 1000000000;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
|
||||||
|
//
|
||||||
|
// Timestamp start = ...;
|
||||||
|
// Duration duration = ...;
|
||||||
|
// Timestamp end = ...;
|
||||||
|
//
|
||||||
|
// end.seconds = start.seconds + duration.seconds;
|
||||||
|
// end.nanos = start.nanos + duration.nanos;
|
||||||
|
//
|
||||||
|
// if (end.nanos < 0) {
|
||||||
|
// end.seconds -= 1;
|
||||||
|
// end.nanos += 1000000000;
|
||||||
|
// } else if (end.nanos >= 1000000000) {
|
||||||
|
// end.seconds += 1;
|
||||||
|
// end.nanos -= 1000000000;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Example 3: Compute Duration from datetime.timedelta in Python.
|
||||||
|
//
|
||||||
|
// td = datetime.timedelta(days=3, minutes=10)
|
||||||
|
// duration = Duration()
|
||||||
|
// duration.FromTimedelta(td)
|
||||||
|
//
|
||||||
|
// # JSON Mapping
|
||||||
|
//
|
||||||
|
// In JSON format, the Duration type is encoded as a string rather than an
|
||||||
|
// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||||
|
// is preceded by the number of seconds, with nanoseconds expressed as
|
||||||
|
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||||
|
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||||
|
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||||
|
// microsecond should be expressed in JSON format as "3.000001s".
|
||||||
|
//
|
||||||
|
//
|
||||||
|
message Duration {
|
||||||
|
|
||||||
|
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||||
|
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||||
|
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||||
|
int64 seconds = 1;
|
||||||
|
|
||||||
|
// Signed fractions of a second at nanosecond resolution of the span
|
||||||
|
// of time. Durations less than one second are represented with a 0
|
||||||
|
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||||
|
// of one second or more, a non-zero value for the `nanos` field must be
|
||||||
|
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||||
|
// to +999,999,999 inclusive.
|
||||||
|
int32 nanos = 2;
|
||||||
|
}
|
43
vendor/github.com/golang/protobuf/ptypes/regen.sh
generated
vendored
Executable file
43
vendor/github.com/golang/protobuf/ptypes/regen.sh
generated
vendored
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
#!/bin/bash -e
|
||||||
|
#
|
||||||
|
# This script fetches and rebuilds the "well-known types" protocol buffers.
|
||||||
|
# To run this you will need protoc and goprotobuf installed;
|
||||||
|
# see https://github.com/golang/protobuf for instructions.
|
||||||
|
# You also need Go and Git installed.
|
||||||
|
|
||||||
|
PKG=github.com/golang/protobuf/ptypes
|
||||||
|
UPSTREAM=https://github.com/google/protobuf
|
||||||
|
UPSTREAM_SUBDIR=src/google/protobuf
|
||||||
|
PROTO_FILES=(any duration empty struct timestamp wrappers)
|
||||||
|
|
||||||
|
function die() {
|
||||||
|
echo 1>&2 $*
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sanity check that the right tools are accessible.
|
||||||
|
for tool in go git protoc protoc-gen-go; do
|
||||||
|
q=$(which $tool) || die "didn't find $tool"
|
||||||
|
echo 1>&2 "$tool: $q"
|
||||||
|
done
|
||||||
|
|
||||||
|
tmpdir=$(mktemp -d -t regen-wkt.XXXXXX)
|
||||||
|
trap 'rm -rf $tmpdir' EXIT
|
||||||
|
|
||||||
|
echo -n 1>&2 "finding package dir... "
|
||||||
|
pkgdir=$(go list -f '{{.Dir}}' $PKG)
|
||||||
|
echo 1>&2 $pkgdir
|
||||||
|
base=$(echo $pkgdir | sed "s,/$PKG\$,,")
|
||||||
|
echo 1>&2 "base: $base"
|
||||||
|
cd "$base"
|
||||||
|
|
||||||
|
echo 1>&2 "fetching latest protos... "
|
||||||
|
git clone -q $UPSTREAM $tmpdir
|
||||||
|
|
||||||
|
for file in ${PROTO_FILES[@]}; do
|
||||||
|
echo 1>&2 "* $file"
|
||||||
|
protoc --go_out=. -I$tmpdir/src $tmpdir/src/google/protobuf/$file.proto || die
|
||||||
|
cp $tmpdir/src/google/protobuf/$file.proto $PKG/$file
|
||||||
|
done
|
||||||
|
|
||||||
|
echo 1>&2 "All OK"
|
134
vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
Normal file
134
vendor/github.com/golang/protobuf/ptypes/timestamp.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
// Go support for Protocol Buffers - Google's data interchange format
|
||||||
|
//
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// https://github.com/golang/protobuf
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
package ptypes
|
||||||
|
|
||||||
|
// This file implements operations on google.protobuf.Timestamp.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
tspb "github.com/golang/protobuf/ptypes/timestamp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Seconds field of the earliest valid Timestamp.
|
||||||
|
// This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
||||||
|
minValidSeconds = -62135596800
|
||||||
|
// Seconds field just after the latest valid Timestamp.
|
||||||
|
// This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
|
||||||
|
maxValidSeconds = 253402300800
|
||||||
|
)
|
||||||
|
|
||||||
|
// validateTimestamp determines whether a Timestamp is valid.
|
||||||
|
// A valid timestamp represents a time in the range
|
||||||
|
// [0001-01-01, 10000-01-01) and has a Nanos field
|
||||||
|
// in the range [0, 1e9).
|
||||||
|
//
|
||||||
|
// If the Timestamp is valid, validateTimestamp returns nil.
|
||||||
|
// Otherwise, it returns an error that describes
|
||||||
|
// the problem.
|
||||||
|
//
|
||||||
|
// Every valid Timestamp can be represented by a time.Time, but the converse is not true.
|
||||||
|
func validateTimestamp(ts *tspb.Timestamp) error {
|
||||||
|
if ts == nil {
|
||||||
|
return errors.New("timestamp: nil Timestamp")
|
||||||
|
}
|
||||||
|
if ts.Seconds < minValidSeconds {
|
||||||
|
return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
|
||||||
|
}
|
||||||
|
if ts.Seconds >= maxValidSeconds {
|
||||||
|
return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
|
||||||
|
}
|
||||||
|
if ts.Nanos < 0 || ts.Nanos >= 1e9 {
|
||||||
|
return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamp converts a google.protobuf.Timestamp proto to a time.Time.
|
||||||
|
// It returns an error if the argument is invalid.
|
||||||
|
//
|
||||||
|
// Unlike most Go functions, if Timestamp returns an error, the first return value
|
||||||
|
// is not the zero time.Time. Instead, it is the value obtained from the
|
||||||
|
// time.Unix function when passed the contents of the Timestamp, in the UTC
|
||||||
|
// locale. This may or may not be a meaningful time; many invalid Timestamps
|
||||||
|
// do map to valid time.Times.
|
||||||
|
//
|
||||||
|
// A nil Timestamp returns an error. The first return value in that case is
|
||||||
|
// undefined.
|
||||||
|
func Timestamp(ts *tspb.Timestamp) (time.Time, error) {
|
||||||
|
// Don't return the zero value on error, because corresponds to a valid
|
||||||
|
// timestamp. Instead return whatever time.Unix gives us.
|
||||||
|
var t time.Time
|
||||||
|
if ts == nil {
|
||||||
|
t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
|
||||||
|
} else {
|
||||||
|
t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
|
||||||
|
}
|
||||||
|
return t, validateTimestamp(ts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampNow returns a google.protobuf.Timestamp for the current time.
|
||||||
|
func TimestampNow() *tspb.Timestamp {
|
||||||
|
ts, err := TimestampProto(time.Now())
|
||||||
|
if err != nil {
|
||||||
|
panic("ptypes: time.Now() out of Timestamp range")
|
||||||
|
}
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
|
||||||
|
// It returns an error if the resulting Timestamp is invalid.
|
||||||
|
func TimestampProto(t time.Time) (*tspb.Timestamp, error) {
|
||||||
|
seconds := t.Unix()
|
||||||
|
nanos := int32(t.Sub(time.Unix(seconds, 0)))
|
||||||
|
ts := &tspb.Timestamp{
|
||||||
|
Seconds: seconds,
|
||||||
|
Nanos: nanos,
|
||||||
|
}
|
||||||
|
if err := validateTimestamp(ts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimestampString returns the RFC 3339 string for valid Timestamps. For invalid
|
||||||
|
// Timestamps, it returns an error message in parentheses.
|
||||||
|
func TimestampString(ts *tspb.Timestamp) string {
|
||||||
|
t, err := Timestamp(ts)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("(%v)", err)
|
||||||
|
}
|
||||||
|
return t.Format(time.RFC3339Nano)
|
||||||
|
}
|
160
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
Normal file
160
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: google/protobuf/timestamp.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package timestamp is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
google/protobuf/timestamp.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Timestamp
|
||||||
|
*/
|
||||||
|
package timestamp
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// A Timestamp represents a point in time independent of any time zone
|
||||||
|
// or calendar, represented as seconds and fractions of seconds at
|
||||||
|
// nanosecond resolution in UTC Epoch time. It is encoded using the
|
||||||
|
// Proleptic Gregorian Calendar which extends the Gregorian calendar
|
||||||
|
// backwards to year one. It is encoded assuming all minutes are 60
|
||||||
|
// seconds long, i.e. leap seconds are "smeared" so that no leap second
|
||||||
|
// table is needed for interpretation. Range is from
|
||||||
|
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
|
||||||
|
// By restricting to that range, we ensure that we can convert to
|
||||||
|
// and from RFC 3339 date strings.
|
||||||
|
// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
|
||||||
|
//
|
||||||
|
// # Examples
|
||||||
|
//
|
||||||
|
// Example 1: Compute Timestamp from POSIX `time()`.
|
||||||
|
//
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds(time(NULL));
|
||||||
|
// timestamp.set_nanos(0);
|
||||||
|
//
|
||||||
|
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
|
||||||
|
//
|
||||||
|
// struct timeval tv;
|
||||||
|
// gettimeofday(&tv, NULL);
|
||||||
|
//
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds(tv.tv_sec);
|
||||||
|
// timestamp.set_nanos(tv.tv_usec * 1000);
|
||||||
|
//
|
||||||
|
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
|
||||||
|
//
|
||||||
|
// FILETIME ft;
|
||||||
|
// GetSystemTimeAsFileTime(&ft);
|
||||||
|
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||||
|
//
|
||||||
|
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
|
||||||
|
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
|
||||||
|
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
|
||||||
|
//
|
||||||
|
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
|
||||||
|
//
|
||||||
|
// long millis = System.currentTimeMillis();
|
||||||
|
//
|
||||||
|
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
|
||||||
|
// .setNanos((int) ((millis % 1000) * 1000000)).build();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Example 5: Compute Timestamp from current time in Python.
|
||||||
|
//
|
||||||
|
// timestamp = Timestamp()
|
||||||
|
// timestamp.GetCurrentTime()
|
||||||
|
//
|
||||||
|
// # JSON Mapping
|
||||||
|
//
|
||||||
|
// In JSON format, the Timestamp type is encoded as a string in the
|
||||||
|
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||||
|
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||||
|
// where {year} is always expressed using four digits while {month}, {day},
|
||||||
|
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||||
|
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||||
|
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||||
|
// is required, though only UTC (as indicated by "Z") is presently supported.
|
||||||
|
//
|
||||||
|
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||||
|
// 01:30 UTC on January 15, 2017.
|
||||||
|
//
|
||||||
|
// In JavaScript, one can convert a Date object to this format using the
|
||||||
|
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
|
||||||
|
// method. In Python, a standard `datetime.datetime` object can be converted
|
||||||
|
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
|
||||||
|
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
|
||||||
|
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||||
|
// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime())
|
||||||
|
// to obtain a formatter capable of generating timestamps in this format.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
type Timestamp struct {
|
||||||
|
// Represents seconds of UTC time since Unix epoch
|
||||||
|
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||||
|
// 9999-12-31T23:59:59Z inclusive.
|
||||||
|
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
|
||||||
|
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||||
|
// second values with fractions must still have non-negative nanos values
|
||||||
|
// that count forward in time. Must be from 0 to 999,999,999
|
||||||
|
// inclusive.
|
||||||
|
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Timestamp) Reset() { *m = Timestamp{} }
|
||||||
|
func (m *Timestamp) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Timestamp) ProtoMessage() {}
|
||||||
|
func (*Timestamp) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
func (*Timestamp) XXX_WellKnownType() string { return "Timestamp" }
|
||||||
|
|
||||||
|
func (m *Timestamp) GetSeconds() int64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Seconds
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Timestamp) GetNanos() int32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Nanos
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Timestamp)(nil), "google.protobuf.Timestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("google/protobuf/timestamp.proto", fileDescriptor0) }
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 191 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xcf, 0xcf, 0x4f,
|
||||||
|
0xcf, 0x49, 0xd5, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0xc9, 0xcc, 0x4d,
|
||||||
|
0x2d, 0x2e, 0x49, 0xcc, 0x2d, 0xd0, 0x03, 0x0b, 0x09, 0xf1, 0x43, 0x14, 0xe8, 0xc1, 0x14, 0x28,
|
||||||
|
0x59, 0x73, 0x71, 0x86, 0xc0, 0xd4, 0x08, 0x49, 0x70, 0xb1, 0x17, 0xa7, 0x26, 0xe7, 0xe7, 0xa5,
|
||||||
|
0x14, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0xc1, 0xb8, 0x42, 0x22, 0x5c, 0xac, 0x79, 0x89,
|
||||||
|
0x79, 0xf9, 0xc5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xac, 0x41, 0x10, 0x8e, 0x53, 0x1d, 0x97, 0x70,
|
||||||
|
0x72, 0x7e, 0xae, 0x1e, 0x9a, 0x99, 0x4e, 0x7c, 0x70, 0x13, 0x03, 0x40, 0x42, 0x01, 0x8c, 0x51,
|
||||||
|
0xda, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0xe9, 0xf9, 0x39, 0x89,
|
||||||
|
0x79, 0xe9, 0x08, 0x27, 0x16, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x23, 0x5c, 0xfa, 0x83, 0x91, 0x71,
|
||||||
|
0x11, 0x13, 0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xc9, 0x01, 0x50, 0xb5, 0x7a,
|
||||||
|
0xe1, 0xa9, 0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x3d, 0x49, 0x6c, 0x60, 0x43,
|
||||||
|
0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x77, 0x4a, 0x07, 0xf7, 0x00, 0x00, 0x00,
|
||||||
|
}
|
133
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto
generated
vendored
Normal file
133
vendor/github.com/golang/protobuf/ptypes/timestamp/timestamp.proto
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. 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.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package google.protobuf;
|
||||||
|
|
||||||
|
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||||
|
option cc_enable_arenas = true;
|
||||||
|
option go_package = "github.com/golang/protobuf/ptypes/timestamp";
|
||||||
|
option java_package = "com.google.protobuf";
|
||||||
|
option java_outer_classname = "TimestampProto";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
option objc_class_prefix = "GPB";
|
||||||
|
|
||||||
|
// A Timestamp represents a point in time independent of any time zone
|
||||||
|
// or calendar, represented as seconds and fractions of seconds at
|
||||||
|
// nanosecond resolution in UTC Epoch time. It is encoded using the
|
||||||
|
// Proleptic Gregorian Calendar which extends the Gregorian calendar
|
||||||
|
// backwards to year one. It is encoded assuming all minutes are 60
|
||||||
|
// seconds long, i.e. leap seconds are "smeared" so that no leap second
|
||||||
|
// table is needed for interpretation. Range is from
|
||||||
|
// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
|
||||||
|
// By restricting to that range, we ensure that we can convert to
|
||||||
|
// and from RFC 3339 date strings.
|
||||||
|
// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
|
||||||
|
//
|
||||||
|
// # Examples
|
||||||
|
//
|
||||||
|
// Example 1: Compute Timestamp from POSIX `time()`.
|
||||||
|
//
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds(time(NULL));
|
||||||
|
// timestamp.set_nanos(0);
|
||||||
|
//
|
||||||
|
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
|
||||||
|
//
|
||||||
|
// struct timeval tv;
|
||||||
|
// gettimeofday(&tv, NULL);
|
||||||
|
//
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds(tv.tv_sec);
|
||||||
|
// timestamp.set_nanos(tv.tv_usec * 1000);
|
||||||
|
//
|
||||||
|
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
|
||||||
|
//
|
||||||
|
// FILETIME ft;
|
||||||
|
// GetSystemTimeAsFileTime(&ft);
|
||||||
|
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||||
|
//
|
||||||
|
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
|
||||||
|
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
|
||||||
|
// Timestamp timestamp;
|
||||||
|
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
|
||||||
|
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
|
||||||
|
//
|
||||||
|
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
|
||||||
|
//
|
||||||
|
// long millis = System.currentTimeMillis();
|
||||||
|
//
|
||||||
|
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
|
||||||
|
// .setNanos((int) ((millis % 1000) * 1000000)).build();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Example 5: Compute Timestamp from current time in Python.
|
||||||
|
//
|
||||||
|
// timestamp = Timestamp()
|
||||||
|
// timestamp.GetCurrentTime()
|
||||||
|
//
|
||||||
|
// # JSON Mapping
|
||||||
|
//
|
||||||
|
// In JSON format, the Timestamp type is encoded as a string in the
|
||||||
|
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||||
|
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||||
|
// where {year} is always expressed using four digits while {month}, {day},
|
||||||
|
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||||
|
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||||
|
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||||
|
// is required, though only UTC (as indicated by "Z") is presently supported.
|
||||||
|
//
|
||||||
|
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||||
|
// 01:30 UTC on January 15, 2017.
|
||||||
|
//
|
||||||
|
// In JavaScript, one can convert a Date object to this format using the
|
||||||
|
// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
|
||||||
|
// method. In Python, a standard `datetime.datetime` object can be converted
|
||||||
|
// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
|
||||||
|
// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
|
||||||
|
// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||||
|
// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime())
|
||||||
|
// to obtain a formatter capable of generating timestamps in this format.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
message Timestamp {
|
||||||
|
|
||||||
|
// Represents seconds of UTC time since Unix epoch
|
||||||
|
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||||
|
// 9999-12-31T23:59:59Z inclusive.
|
||||||
|
int64 seconds = 1;
|
||||||
|
|
||||||
|
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||||
|
// second values with fractions must still have non-negative nanos values
|
||||||
|
// that count forward in time. Must be from 0 to 999,999,999
|
||||||
|
// inclusive.
|
||||||
|
int32 nanos = 2;
|
||||||
|
}
|
3
vendor/golang.org/x/net/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/net/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/net/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/net/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/net/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/net/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009 The Go 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 Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/golang.org/x/net/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/net/PATENTS
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
54
vendor/golang.org/x/net/context/context.go
generated
vendored
Normal file
54
vendor/golang.org/x/net/context/context.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2014 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 context defines the Context type, which carries deadlines,
|
||||||
|
// cancelation signals, and other request-scoped values across API boundaries
|
||||||
|
// and between processes.
|
||||||
|
//
|
||||||
|
// Incoming requests to a server should create a Context, and outgoing calls to
|
||||||
|
// servers should accept a Context. The chain of function calls between must
|
||||||
|
// propagate the Context, optionally replacing it with a modified copy created
|
||||||
|
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
||||||
|
//
|
||||||
|
// Programs that use Contexts should follow these rules to keep interfaces
|
||||||
|
// consistent across packages and enable static analysis tools to check context
|
||||||
|
// propagation:
|
||||||
|
//
|
||||||
|
// Do not store Contexts inside a struct type; instead, pass a Context
|
||||||
|
// explicitly to each function that needs it. The Context should be the first
|
||||||
|
// parameter, typically named ctx:
|
||||||
|
//
|
||||||
|
// func DoSomething(ctx context.Context, arg Arg) error {
|
||||||
|
// // ... use ctx ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||||
|
// if you are unsure about which Context to use.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
//
|
||||||
|
// The same Context may be passed to functions running in different goroutines;
|
||||||
|
// Contexts are safe for simultaneous use by multiple goroutines.
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/context for example code for a server that uses
|
||||||
|
// Contexts.
|
||||||
|
package context
|
||||||
|
|
||||||
|
// Background returns a non-nil, empty Context. It is never canceled, has no
|
||||||
|
// values, and has no deadline. It is typically used by the main function,
|
||||||
|
// initialization, and tests, and as the top-level Context for incoming
|
||||||
|
// requests.
|
||||||
|
func Background() Context {
|
||||||
|
return background
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||||
|
// it's unclear which Context to use or it is not yet available (because the
|
||||||
|
// surrounding function has not yet been extended to accept a Context
|
||||||
|
// parameter). TODO is recognized by static analysis tools that determine
|
||||||
|
// whether Contexts are propagated correctly in a program.
|
||||||
|
func TODO() Context {
|
||||||
|
return todo
|
||||||
|
}
|
72
vendor/golang.org/x/net/context/go17.go
generated
vendored
Normal file
72
vendor/golang.org/x/net/context/go17.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context" // standard library's context, as of Go 1.7
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
todo = context.TODO()
|
||||||
|
background = context.Background()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Canceled is the error returned by Context.Err when the context is canceled.
|
||||||
|
var Canceled = context.Canceled
|
||||||
|
|
||||||
|
// DeadlineExceeded is the error returned by Context.Err when the context's
|
||||||
|
// deadline passes.
|
||||||
|
var DeadlineExceeded = context.DeadlineExceeded
|
||||||
|
|
||||||
|
// WithCancel returns a copy of parent with a new Done channel. The returned
|
||||||
|
// context's Done channel is closed when the returned cancel function is called
|
||||||
|
// or when the parent context's Done channel is closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||||
|
ctx, f := context.WithCancel(parent)
|
||||||
|
return ctx, CancelFunc(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
|
// closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
|
ctx, f := context.WithDeadline(parent, deadline)
|
||||||
|
return ctx, CancelFunc(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete:
|
||||||
|
//
|
||||||
|
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
|
||||||
|
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||||
|
// defer cancel() // releases resources if slowOperation completes before timeout elapses
|
||||||
|
// return slowOperation(ctx)
|
||||||
|
// }
|
||||||
|
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
|
||||||
|
return WithDeadline(parent, time.Now().Add(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValue returns a copy of parent in which the value associated with key is
|
||||||
|
// val.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||||
|
return context.WithValue(parent, key, val)
|
||||||
|
}
|
20
vendor/golang.org/x/net/context/go19.go
generated
vendored
Normal file
20
vendor/golang.org/x/net/context/go19.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import "context" // standard library's context, as of Go 1.7
|
||||||
|
|
||||||
|
// A Context carries a deadline, a cancelation signal, and other values across
|
||||||
|
// API boundaries.
|
||||||
|
//
|
||||||
|
// Context's methods may be called by multiple goroutines simultaneously.
|
||||||
|
type Context = context.Context
|
||||||
|
|
||||||
|
// A CancelFunc tells an operation to abandon its work.
|
||||||
|
// A CancelFunc does not wait for the work to stop.
|
||||||
|
// After the first call, subsequent calls to a CancelFunc do nothing.
|
||||||
|
type CancelFunc = context.CancelFunc
|
300
vendor/golang.org/x/net/context/pre_go17.go
generated
vendored
Normal file
300
vendor/golang.org/x/net/context/pre_go17.go
generated
vendored
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||||
|
// struct{}, since vars of this type must have distinct addresses.
|
||||||
|
type emptyCtx int
|
||||||
|
|
||||||
|
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Done() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Value(key interface{}) interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emptyCtx) String() string {
|
||||||
|
switch e {
|
||||||
|
case background:
|
||||||
|
return "context.Background"
|
||||||
|
case todo:
|
||||||
|
return "context.TODO"
|
||||||
|
}
|
||||||
|
return "unknown empty Context"
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
background = new(emptyCtx)
|
||||||
|
todo = new(emptyCtx)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Canceled is the error returned by Context.Err when the context is canceled.
|
||||||
|
var Canceled = errors.New("context canceled")
|
||||||
|
|
||||||
|
// DeadlineExceeded is the error returned by Context.Err when the context's
|
||||||
|
// deadline passes.
|
||||||
|
var DeadlineExceeded = errors.New("context deadline exceeded")
|
||||||
|
|
||||||
|
// WithCancel returns a copy of parent with a new Done channel. The returned
|
||||||
|
// context's Done channel is closed when the returned cancel function is called
|
||||||
|
// or when the parent context's Done channel is closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||||
|
c := newCancelCtx(parent)
|
||||||
|
propagateCancel(parent, c)
|
||||||
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// newCancelCtx returns an initialized cancelCtx.
|
||||||
|
func newCancelCtx(parent Context) *cancelCtx {
|
||||||
|
return &cancelCtx{
|
||||||
|
Context: parent,
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// propagateCancel arranges for child to be canceled when parent is.
|
||||||
|
func propagateCancel(parent Context, child canceler) {
|
||||||
|
if parent.Done() == nil {
|
||||||
|
return // parent is never canceled
|
||||||
|
}
|
||||||
|
if p, ok := parentCancelCtx(parent); ok {
|
||||||
|
p.mu.Lock()
|
||||||
|
if p.err != nil {
|
||||||
|
// parent has already been canceled
|
||||||
|
child.cancel(false, p.err)
|
||||||
|
} else {
|
||||||
|
if p.children == nil {
|
||||||
|
p.children = make(map[canceler]bool)
|
||||||
|
}
|
||||||
|
p.children[child] = true
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
} else {
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-parent.Done():
|
||||||
|
child.cancel(false, parent.Err())
|
||||||
|
case <-child.Done():
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parentCancelCtx follows a chain of parent references until it finds a
|
||||||
|
// *cancelCtx. This function understands how each of the concrete types in this
|
||||||
|
// package represents its parent.
|
||||||
|
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||||
|
for {
|
||||||
|
switch c := parent.(type) {
|
||||||
|
case *cancelCtx:
|
||||||
|
return c, true
|
||||||
|
case *timerCtx:
|
||||||
|
return c.cancelCtx, true
|
||||||
|
case *valueCtx:
|
||||||
|
parent = c.Context
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeChild removes a context from its parent.
|
||||||
|
func removeChild(parent Context, child canceler) {
|
||||||
|
p, ok := parentCancelCtx(parent)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.mu.Lock()
|
||||||
|
if p.children != nil {
|
||||||
|
delete(p.children, child)
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A canceler is a context type that can be canceled directly. The
|
||||||
|
// implementations are *cancelCtx and *timerCtx.
|
||||||
|
type canceler interface {
|
||||||
|
cancel(removeFromParent bool, err error)
|
||||||
|
Done() <-chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||||
|
// that implement canceler.
|
||||||
|
type cancelCtx struct {
|
||||||
|
Context
|
||||||
|
|
||||||
|
done chan struct{} // closed by the first cancel call.
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
children map[canceler]bool // set to nil by the first cancel call
|
||||||
|
err error // set to non-nil by the first cancel call
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) Done() <-chan struct{} {
|
||||||
|
return c.done
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) Err() error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithCancel", c.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancel closes c.done, cancels each of c's children, and, if
|
||||||
|
// removeFromParent is true, removes c from its parent's children.
|
||||||
|
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||||
|
if err == nil {
|
||||||
|
panic("context: internal error: missing cancel error")
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.err != nil {
|
||||||
|
c.mu.Unlock()
|
||||||
|
return // already canceled
|
||||||
|
}
|
||||||
|
c.err = err
|
||||||
|
close(c.done)
|
||||||
|
for child := range c.children {
|
||||||
|
// NOTE: acquiring the child's lock while holding parent's lock.
|
||||||
|
child.cancel(false, err)
|
||||||
|
}
|
||||||
|
c.children = nil
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
if removeFromParent {
|
||||||
|
removeChild(c.Context, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
|
// closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
|
if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
|
||||||
|
// The current deadline is already sooner than the new one.
|
||||||
|
return WithCancel(parent)
|
||||||
|
}
|
||||||
|
c := &timerCtx{
|
||||||
|
cancelCtx: newCancelCtx(parent),
|
||||||
|
deadline: deadline,
|
||||||
|
}
|
||||||
|
propagateCancel(parent, c)
|
||||||
|
d := deadline.Sub(time.Now())
|
||||||
|
if d <= 0 {
|
||||||
|
c.cancel(true, DeadlineExceeded) // deadline has already passed
|
||||||
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if c.err == nil {
|
||||||
|
c.timer = time.AfterFunc(d, func() {
|
||||||
|
c.cancel(true, DeadlineExceeded)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||||
|
// implement Done and Err. It implements cancel by stopping its timer then
|
||||||
|
// delegating to cancelCtx.cancel.
|
||||||
|
type timerCtx struct {
|
||||||
|
*cancelCtx
|
||||||
|
timer *time.Timer // Under cancelCtx.mu.
|
||||||
|
|
||||||
|
deadline time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return c.deadline, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) cancel(removeFromParent bool, err error) {
|
||||||
|
c.cancelCtx.cancel(false, err)
|
||||||
|
if removeFromParent {
|
||||||
|
// Remove this timerCtx from its parent cancelCtx's children.
|
||||||
|
removeChild(c.cancelCtx.Context, c)
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.timer != nil {
|
||||||
|
c.timer.Stop()
|
||||||
|
c.timer = nil
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete:
|
||||||
|
//
|
||||||
|
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
|
||||||
|
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||||
|
// defer cancel() // releases resources if slowOperation completes before timeout elapses
|
||||||
|
// return slowOperation(ctx)
|
||||||
|
// }
|
||||||
|
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
|
||||||
|
return WithDeadline(parent, time.Now().Add(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValue returns a copy of parent in which the value associated with key is
|
||||||
|
// val.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||||
|
return &valueCtx{parent, key, val}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||||
|
// delegates all other calls to the embedded Context.
|
||||||
|
type valueCtx struct {
|
||||||
|
Context
|
||||||
|
key, val interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *valueCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *valueCtx) Value(key interface{}) interface{} {
|
||||||
|
if c.key == key {
|
||||||
|
return c.val
|
||||||
|
}
|
||||||
|
return c.Context.Value(key)
|
||||||
|
}
|
109
vendor/golang.org/x/net/context/pre_go19.go
generated
vendored
Normal file
109
vendor/golang.org/x/net/context/pre_go19.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// A Context carries a deadline, a cancelation signal, and other values across
|
||||||
|
// API boundaries.
|
||||||
|
//
|
||||||
|
// Context's methods may be called by multiple goroutines simultaneously.
|
||||||
|
type Context interface {
|
||||||
|
// Deadline returns the time when work done on behalf of this context
|
||||||
|
// should be canceled. Deadline returns ok==false when no deadline is
|
||||||
|
// set. Successive calls to Deadline return the same results.
|
||||||
|
Deadline() (deadline time.Time, ok bool)
|
||||||
|
|
||||||
|
// Done returns a channel that's closed when work done on behalf of this
|
||||||
|
// context should be canceled. Done may return nil if this context can
|
||||||
|
// never be canceled. Successive calls to Done return the same value.
|
||||||
|
//
|
||||||
|
// WithCancel arranges for Done to be closed when cancel is called;
|
||||||
|
// WithDeadline arranges for Done to be closed when the deadline
|
||||||
|
// expires; WithTimeout arranges for Done to be closed when the timeout
|
||||||
|
// elapses.
|
||||||
|
//
|
||||||
|
// Done is provided for use in select statements:
|
||||||
|
//
|
||||||
|
// // Stream generates values with DoSomething and sends them to out
|
||||||
|
// // until DoSomething returns an error or ctx.Done is closed.
|
||||||
|
// func Stream(ctx context.Context, out chan<- Value) error {
|
||||||
|
// for {
|
||||||
|
// v, err := DoSomething(ctx)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// select {
|
||||||
|
// case <-ctx.Done():
|
||||||
|
// return ctx.Err()
|
||||||
|
// case out <- v:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/pipelines for more examples of how to use
|
||||||
|
// a Done channel for cancelation.
|
||||||
|
Done() <-chan struct{}
|
||||||
|
|
||||||
|
// Err returns a non-nil error value after Done is closed. Err returns
|
||||||
|
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||||
|
// context's deadline passed. No other values for Err are defined.
|
||||||
|
// After Done is closed, successive calls to Err return the same value.
|
||||||
|
Err() error
|
||||||
|
|
||||||
|
// Value returns the value associated with this context for key, or nil
|
||||||
|
// if no value is associated with key. Successive calls to Value with
|
||||||
|
// the same key returns the same result.
|
||||||
|
//
|
||||||
|
// Use context values only for request-scoped data that transits
|
||||||
|
// processes and API boundaries, not for passing optional parameters to
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
|
// A key identifies a specific value in a Context. Functions that wish
|
||||||
|
// to store values in Context typically allocate a key in a global
|
||||||
|
// variable then use that key as the argument to context.WithValue and
|
||||||
|
// Context.Value. A key can be any type that supports equality;
|
||||||
|
// packages should define keys as an unexported type to avoid
|
||||||
|
// collisions.
|
||||||
|
//
|
||||||
|
// Packages that define a Context key should provide type-safe accessors
|
||||||
|
// for the values stores using that key:
|
||||||
|
//
|
||||||
|
// // Package user defines a User type that's stored in Contexts.
|
||||||
|
// package user
|
||||||
|
//
|
||||||
|
// import "golang.org/x/net/context"
|
||||||
|
//
|
||||||
|
// // User is the type of value stored in the Contexts.
|
||||||
|
// type User struct {...}
|
||||||
|
//
|
||||||
|
// // key is an unexported type for keys defined in this package.
|
||||||
|
// // This prevents collisions with keys defined in other packages.
|
||||||
|
// type key int
|
||||||
|
//
|
||||||
|
// // userKey is the key for user.User values in Contexts. It is
|
||||||
|
// // unexported; clients use user.NewContext and user.FromContext
|
||||||
|
// // instead of using this key directly.
|
||||||
|
// var userKey key = 0
|
||||||
|
//
|
||||||
|
// // NewContext returns a new Context that carries value u.
|
||||||
|
// func NewContext(ctx context.Context, u *User) context.Context {
|
||||||
|
// return context.WithValue(ctx, userKey, u)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // FromContext returns the User value stored in ctx, if any.
|
||||||
|
// func FromContext(ctx context.Context) (*User, bool) {
|
||||||
|
// u, ok := ctx.Value(userKey).(*User)
|
||||||
|
// return u, ok
|
||||||
|
// }
|
||||||
|
Value(key interface{}) interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CancelFunc tells an operation to abandon its work.
|
||||||
|
// A CancelFunc does not wait for the work to stop.
|
||||||
|
// After the first call, subsequent calls to a CancelFunc do nothing.
|
||||||
|
type CancelFunc func()
|
2
vendor/golang.org/x/net/http2/.gitignore
generated
vendored
Normal file
2
vendor/golang.org/x/net/http2/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*~
|
||||||
|
h2i/h2i
|
51
vendor/golang.org/x/net/http2/Dockerfile
generated
vendored
Normal file
51
vendor/golang.org/x/net/http2/Dockerfile
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#
|
||||||
|
# This Dockerfile builds a recent curl with HTTP/2 client support, using
|
||||||
|
# a recent nghttp2 build.
|
||||||
|
#
|
||||||
|
# See the Makefile for how to tag it. If Docker and that image is found, the
|
||||||
|
# Go tests use this curl binary for integration tests.
|
||||||
|
#
|
||||||
|
|
||||||
|
FROM ubuntu:trusty
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get upgrade -y && \
|
||||||
|
apt-get install -y git-core build-essential wget
|
||||||
|
|
||||||
|
RUN apt-get install -y --no-install-recommends \
|
||||||
|
autotools-dev libtool pkg-config zlib1g-dev \
|
||||||
|
libcunit1-dev libssl-dev libxml2-dev libevent-dev \
|
||||||
|
automake autoconf
|
||||||
|
|
||||||
|
# The list of packages nghttp2 recommends for h2load:
|
||||||
|
RUN apt-get install -y --no-install-recommends make binutils \
|
||||||
|
autoconf automake autotools-dev \
|
||||||
|
libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev \
|
||||||
|
libev-dev libevent-dev libjansson-dev libjemalloc-dev \
|
||||||
|
cython python3.4-dev python-setuptools
|
||||||
|
|
||||||
|
# Note: setting NGHTTP2_VER before the git clone, so an old git clone isn't cached:
|
||||||
|
ENV NGHTTP2_VER 895da9a
|
||||||
|
RUN cd /root && git clone https://github.com/tatsuhiro-t/nghttp2.git
|
||||||
|
|
||||||
|
WORKDIR /root/nghttp2
|
||||||
|
RUN git reset --hard $NGHTTP2_VER
|
||||||
|
RUN autoreconf -i
|
||||||
|
RUN automake
|
||||||
|
RUN autoconf
|
||||||
|
RUN ./configure
|
||||||
|
RUN make
|
||||||
|
RUN make install
|
||||||
|
|
||||||
|
WORKDIR /root
|
||||||
|
RUN wget http://curl.haxx.se/download/curl-7.45.0.tar.gz
|
||||||
|
RUN tar -zxvf curl-7.45.0.tar.gz
|
||||||
|
WORKDIR /root/curl-7.45.0
|
||||||
|
RUN ./configure --with-ssl --with-nghttp2=/usr/local
|
||||||
|
RUN make
|
||||||
|
RUN make install
|
||||||
|
RUN ldconfig
|
||||||
|
|
||||||
|
CMD ["-h"]
|
||||||
|
ENTRYPOINT ["/usr/local/bin/curl"]
|
||||||
|
|
3
vendor/golang.org/x/net/http2/Makefile
generated
vendored
Normal file
3
vendor/golang.org/x/net/http2/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
curlimage:
|
||||||
|
docker build -t gohttp2/curl .
|
||||||
|
|
20
vendor/golang.org/x/net/http2/README
generated
vendored
Normal file
20
vendor/golang.org/x/net/http2/README
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
This is a work-in-progress HTTP/2 implementation for Go.
|
||||||
|
|
||||||
|
It will eventually live in the Go standard library and won't require
|
||||||
|
any changes to your code to use. It will just be automatic.
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
* The server support is pretty good. A few things are missing
|
||||||
|
but are being worked on.
|
||||||
|
* The client work has just started but shares a lot of code
|
||||||
|
is coming along much quicker.
|
||||||
|
|
||||||
|
Docs are at https://godoc.org/golang.org/x/net/http2
|
||||||
|
|
||||||
|
Demo test server at https://http2.golang.org/
|
||||||
|
|
||||||
|
Help & bug reports welcome!
|
||||||
|
|
||||||
|
Contributing: https://golang.org/doc/contribute.html
|
||||||
|
Bugs: https://golang.org/issue/new?title=x/net/http2:+
|
641
vendor/golang.org/x/net/http2/ciphers.go
generated
vendored
Normal file
641
vendor/golang.org/x/net/http2/ciphers.go
generated
vendored
Normal file
|
@ -0,0 +1,641 @@
|
||||||
|
// Copyright 2017 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 http2
|
||||||
|
|
||||||
|
// A list of the possible cipher suite ids. Taken from
|
||||||
|
// http://www.iana.org/assignments/tls-parameters/tls-parameters.txt
|
||||||
|
|
||||||
|
const (
|
||||||
|
cipher_TLS_NULL_WITH_NULL_NULL uint16 = 0x0000
|
||||||
|
cipher_TLS_RSA_WITH_NULL_MD5 uint16 = 0x0001
|
||||||
|
cipher_TLS_RSA_WITH_NULL_SHA uint16 = 0x0002
|
||||||
|
cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0003
|
||||||
|
cipher_TLS_RSA_WITH_RC4_128_MD5 uint16 = 0x0004
|
||||||
|
cipher_TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
|
||||||
|
cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x0006
|
||||||
|
cipher_TLS_RSA_WITH_IDEA_CBC_SHA uint16 = 0x0007
|
||||||
|
cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0008
|
||||||
|
cipher_TLS_RSA_WITH_DES_CBC_SHA uint16 = 0x0009
|
||||||
|
cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000A
|
||||||
|
cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000B
|
||||||
|
cipher_TLS_DH_DSS_WITH_DES_CBC_SHA uint16 = 0x000C
|
||||||
|
cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x000D
|
||||||
|
cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x000E
|
||||||
|
cipher_TLS_DH_RSA_WITH_DES_CBC_SHA uint16 = 0x000F
|
||||||
|
cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0010
|
||||||
|
cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0011
|
||||||
|
cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA uint16 = 0x0012
|
||||||
|
cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0x0013
|
||||||
|
cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0014
|
||||||
|
cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA uint16 = 0x0015
|
||||||
|
cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x0016
|
||||||
|
cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 uint16 = 0x0017
|
||||||
|
cipher_TLS_DH_anon_WITH_RC4_128_MD5 uint16 = 0x0018
|
||||||
|
cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA uint16 = 0x0019
|
||||||
|
cipher_TLS_DH_anon_WITH_DES_CBC_SHA uint16 = 0x001A
|
||||||
|
cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0x001B
|
||||||
|
// Reserved uint16 = 0x001C-1D
|
||||||
|
cipher_TLS_KRB5_WITH_DES_CBC_SHA uint16 = 0x001E
|
||||||
|
cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA uint16 = 0x001F
|
||||||
|
cipher_TLS_KRB5_WITH_RC4_128_SHA uint16 = 0x0020
|
||||||
|
cipher_TLS_KRB5_WITH_IDEA_CBC_SHA uint16 = 0x0021
|
||||||
|
cipher_TLS_KRB5_WITH_DES_CBC_MD5 uint16 = 0x0022
|
||||||
|
cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5 uint16 = 0x0023
|
||||||
|
cipher_TLS_KRB5_WITH_RC4_128_MD5 uint16 = 0x0024
|
||||||
|
cipher_TLS_KRB5_WITH_IDEA_CBC_MD5 uint16 = 0x0025
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA uint16 = 0x0026
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA uint16 = 0x0027
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA uint16 = 0x0028
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 uint16 = 0x0029
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 uint16 = 0x002A
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5 uint16 = 0x002B
|
||||||
|
cipher_TLS_PSK_WITH_NULL_SHA uint16 = 0x002C
|
||||||
|
cipher_TLS_DHE_PSK_WITH_NULL_SHA uint16 = 0x002D
|
||||||
|
cipher_TLS_RSA_PSK_WITH_NULL_SHA uint16 = 0x002E
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002F
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0030
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0031
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA uint16 = 0x0032
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0x0033
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA uint16 = 0x0034
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0036
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0037
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA uint16 = 0x0038
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0039
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA uint16 = 0x003A
|
||||||
|
cipher_TLS_RSA_WITH_NULL_SHA256 uint16 = 0x003B
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003C
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003D
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x003E
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003F
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 uint16 = 0x0040
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0041
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0042
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0043
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0044
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0045
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA uint16 = 0x0046
|
||||||
|
// Reserved uint16 = 0x0047-4F
|
||||||
|
// Reserved uint16 = 0x0050-58
|
||||||
|
// Reserved uint16 = 0x0059-5C
|
||||||
|
// Unassigned uint16 = 0x005D-5F
|
||||||
|
// Reserved uint16 = 0x0060-66
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x0068
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x0069
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 uint16 = 0x006A
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006B
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256 uint16 = 0x006C
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256 uint16 = 0x006D
|
||||||
|
// Unassigned uint16 = 0x006E-83
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0084
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0085
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0086
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0087
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0088
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA uint16 = 0x0089
|
||||||
|
cipher_TLS_PSK_WITH_RC4_128_SHA uint16 = 0x008A
|
||||||
|
cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008B
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008C
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008D
|
||||||
|
cipher_TLS_DHE_PSK_WITH_RC4_128_SHA uint16 = 0x008E
|
||||||
|
cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x008F
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0090
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0091
|
||||||
|
cipher_TLS_RSA_PSK_WITH_RC4_128_SHA uint16 = 0x0092
|
||||||
|
cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0x0093
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA uint16 = 0x0094
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA uint16 = 0x0095
|
||||||
|
cipher_TLS_RSA_WITH_SEED_CBC_SHA uint16 = 0x0096
|
||||||
|
cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA uint16 = 0x0097
|
||||||
|
cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA uint16 = 0x0098
|
||||||
|
cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA uint16 = 0x0099
|
||||||
|
cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA uint16 = 0x009A
|
||||||
|
cipher_TLS_DH_anon_WITH_SEED_CBC_SHA uint16 = 0x009B
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009C
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009D
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009E
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009F
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x00A0
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x00A1
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A2
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A3
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 uint16 = 0x00A4
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 uint16 = 0x00A5
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256 uint16 = 0x00A6
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384 uint16 = 0x00A7
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00A8
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00A9
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AA
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AB
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0x00AC
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0x00AD
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00AE
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00AF
|
||||||
|
cipher_TLS_PSK_WITH_NULL_SHA256 uint16 = 0x00B0
|
||||||
|
cipher_TLS_PSK_WITH_NULL_SHA384 uint16 = 0x00B1
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B2
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B3
|
||||||
|
cipher_TLS_DHE_PSK_WITH_NULL_SHA256 uint16 = 0x00B4
|
||||||
|
cipher_TLS_DHE_PSK_WITH_NULL_SHA384 uint16 = 0x00B5
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0x00B6
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0x00B7
|
||||||
|
cipher_TLS_RSA_PSK_WITH_NULL_SHA256 uint16 = 0x00B8
|
||||||
|
cipher_TLS_RSA_PSK_WITH_NULL_SHA384 uint16 = 0x00B9
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BA
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BB
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BC
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BD
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BE
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0x00BF
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C0
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C1
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C2
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C3
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C4
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 uint16 = 0x00C5
|
||||||
|
// Unassigned uint16 = 0x00C6-FE
|
||||||
|
cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV uint16 = 0x00FF
|
||||||
|
// Unassigned uint16 = 0x01-55,*
|
||||||
|
cipher_TLS_FALLBACK_SCSV uint16 = 0x5600
|
||||||
|
// Unassigned uint16 = 0x5601 - 0xC000
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA uint16 = 0xC001
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA uint16 = 0xC002
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC003
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC004
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC005
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA uint16 = 0xC006
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xC007
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC008
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xC009
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xC00A
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_NULL_SHA uint16 = 0xC00B
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA uint16 = 0xC00C
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC00D
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC00E
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC00F
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_NULL_SHA uint16 = 0xC010
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xC011
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC012
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC013
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC014
|
||||||
|
cipher_TLS_ECDH_anon_WITH_NULL_SHA uint16 = 0xC015
|
||||||
|
cipher_TLS_ECDH_anon_WITH_RC4_128_SHA uint16 = 0xC016
|
||||||
|
cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA uint16 = 0xC017
|
||||||
|
cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA uint16 = 0xC018
|
||||||
|
cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA uint16 = 0xC019
|
||||||
|
cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01A
|
||||||
|
cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01B
|
||||||
|
cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA uint16 = 0xC01C
|
||||||
|
cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA uint16 = 0xC01D
|
||||||
|
cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA uint16 = 0xC01E
|
||||||
|
cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA uint16 = 0xC01F
|
||||||
|
cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA uint16 = 0xC020
|
||||||
|
cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA uint16 = 0xC021
|
||||||
|
cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA uint16 = 0xC022
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC023
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC024
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC025
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC026
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC027
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC028
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xC029
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 uint16 = 0xC02A
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02B
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02C
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02D
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC02E
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC02F
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC030
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xC031
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xC032
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA uint16 = 0xC033
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA uint16 = 0xC034
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA uint16 = 0xC035
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA uint16 = 0xC036
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 uint16 = 0xC037
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 uint16 = 0xC038
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA uint16 = 0xC039
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256 uint16 = 0xC03A
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384 uint16 = 0xC03B
|
||||||
|
cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03C
|
||||||
|
cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03D
|
||||||
|
cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC03E
|
||||||
|
cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC03F
|
||||||
|
cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC040
|
||||||
|
cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC041
|
||||||
|
cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC042
|
||||||
|
cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC043
|
||||||
|
cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC044
|
||||||
|
cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC045
|
||||||
|
cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC046
|
||||||
|
cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC047
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC048
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC049
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04A
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04B
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04C
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04D
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC04E
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC04F
|
||||||
|
cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC050
|
||||||
|
cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC051
|
||||||
|
cipher_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC052
|
||||||
|
cipher_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC053
|
||||||
|
cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC054
|
||||||
|
cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC055
|
||||||
|
cipher_TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC056
|
||||||
|
cipher_TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC057
|
||||||
|
cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC058
|
||||||
|
cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC059
|
||||||
|
cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05A
|
||||||
|
cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05B
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05C
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05D
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC05E
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC05F
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC060
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC061
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC062
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC063
|
||||||
|
cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC064
|
||||||
|
cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC065
|
||||||
|
cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC066
|
||||||
|
cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC067
|
||||||
|
cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC068
|
||||||
|
cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC069
|
||||||
|
cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06A
|
||||||
|
cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06B
|
||||||
|
cipher_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06C
|
||||||
|
cipher_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06D
|
||||||
|
cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 uint16 = 0xC06E
|
||||||
|
cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 uint16 = 0xC06F
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 uint16 = 0xC070
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 uint16 = 0xC071
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC072
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC073
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC074
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC075
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC076
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC077
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC078
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC079
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07A
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07B
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07C
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07D
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC07E
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC07F
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC080
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC081
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC082
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC083
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC084
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC085
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC086
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC087
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC088
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC089
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08A
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08B
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08C
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08D
|
||||||
|
cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC08E
|
||||||
|
cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC08F
|
||||||
|
cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC090
|
||||||
|
cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC091
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 uint16 = 0xC092
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 uint16 = 0xC093
|
||||||
|
cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC094
|
||||||
|
cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC095
|
||||||
|
cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC096
|
||||||
|
cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC097
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC098
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC099
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 uint16 = 0xC09A
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 uint16 = 0xC09B
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_CCM uint16 = 0xC09C
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_CCM uint16 = 0xC09D
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_128_CCM uint16 = 0xC09E
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_256_CCM uint16 = 0xC09F
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A0
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A1
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_128_CCM_8 uint16 = 0xC0A2
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_256_CCM_8 uint16 = 0xC0A3
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_CCM uint16 = 0xC0A4
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_CCM uint16 = 0xC0A5
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_128_CCM uint16 = 0xC0A6
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_256_CCM uint16 = 0xC0A7
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_CCM_8 uint16 = 0xC0A8
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_CCM_8 uint16 = 0xC0A9
|
||||||
|
cipher_TLS_PSK_DHE_WITH_AES_128_CCM_8 uint16 = 0xC0AA
|
||||||
|
cipher_TLS_PSK_DHE_WITH_AES_256_CCM_8 uint16 = 0xC0AB
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM uint16 = 0xC0AC
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM uint16 = 0xC0AD
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 uint16 = 0xC0AE
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 uint16 = 0xC0AF
|
||||||
|
// Unassigned uint16 = 0xC0B0-FF
|
||||||
|
// Unassigned uint16 = 0xC1-CB,*
|
||||||
|
// Unassigned uint16 = 0xCC00-A7
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA8
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCA9
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAA
|
||||||
|
cipher_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAB
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAC
|
||||||
|
cipher_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAD
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xCCAE
|
||||||
|
)
|
||||||
|
|
||||||
|
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
|
||||||
|
// References:
|
||||||
|
// https://tools.ietf.org/html/rfc7540#appendix-A
|
||||||
|
// Reject cipher suites from Appendix A.
|
||||||
|
// "This list includes those cipher suites that do not
|
||||||
|
// offer an ephemeral key exchange and those that are
|
||||||
|
// based on the TLS null, stream or block cipher type"
|
||||||
|
func isBadCipher(cipher uint16) bool {
|
||||||
|
switch cipher {
|
||||||
|
case cipher_TLS_NULL_WITH_NULL_NULL,
|
||||||
|
cipher_TLS_RSA_WITH_NULL_MD5,
|
||||||
|
cipher_TLS_RSA_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_RSA_EXPORT_WITH_RC4_40_MD5,
|
||||||
|
cipher_TLS_RSA_WITH_RC4_128_MD5,
|
||||||
|
cipher_TLS_RSA_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,
|
||||||
|
cipher_TLS_RSA_WITH_IDEA_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_EXPORT_WITH_DES40_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_WITH_DES_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA,
|
||||||
|
cipher_TLS_DH_DSS_WITH_DES_CBC_SHA,
|
||||||
|
cipher_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA,
|
||||||
|
cipher_TLS_DH_RSA_WITH_DES_CBC_SHA,
|
||||||
|
cipher_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_DES_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_DES_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_DH_anon_EXPORT_WITH_RC4_40_MD5,
|
||||||
|
cipher_TLS_DH_anon_WITH_RC4_128_MD5,
|
||||||
|
cipher_TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA,
|
||||||
|
cipher_TLS_DH_anon_WITH_DES_CBC_SHA,
|
||||||
|
cipher_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_KRB5_WITH_DES_CBC_SHA,
|
||||||
|
cipher_TLS_KRB5_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_KRB5_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_KRB5_WITH_IDEA_CBC_SHA,
|
||||||
|
cipher_TLS_KRB5_WITH_DES_CBC_MD5,
|
||||||
|
cipher_TLS_KRB5_WITH_3DES_EDE_CBC_MD5,
|
||||||
|
cipher_TLS_KRB5_WITH_RC4_128_MD5,
|
||||||
|
cipher_TLS_KRB5_WITH_IDEA_CBC_MD5,
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA,
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA,
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_RC4_40_SHA,
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5,
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5,
|
||||||
|
cipher_TLS_KRB5_EXPORT_WITH_RC4_40_MD5,
|
||||||
|
cipher_TLS_PSK_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_WITH_NULL_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA,
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_256_CBC_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA,
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA,
|
||||||
|
cipher_TLS_PSK_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_PSK_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_WITH_SEED_CBC_SHA,
|
||||||
|
cipher_TLS_DH_DSS_WITH_SEED_CBC_SHA,
|
||||||
|
cipher_TLS_DH_RSA_WITH_SEED_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_SEED_CBC_SHA,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_SEED_CBC_SHA,
|
||||||
|
cipher_TLS_DH_anon_WITH_SEED_CBC_SHA,
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_anon_WITH_AES_256_GCM_SHA384,
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_GCM_SHA256,
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_GCM_SHA384,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_CBC_SHA384,
|
||||||
|
cipher_TLS_PSK_WITH_NULL_SHA256,
|
||||||
|
cipher_TLS_PSK_WITH_NULL_SHA384,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_NULL_SHA256,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_NULL_SHA384,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_NULL_SHA256,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_NULL_SHA384,
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256,
|
||||||
|
cipher_TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_ECDH_anon_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_ECDH_anon_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_ECDH_anon_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_RC4_128_SHA,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA256,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_NULL_SHA384,
|
||||||
|
cipher_TLS_RSA_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_DH_anon_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DH_anon_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_RSA_WITH_ARIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_ARIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_anon_WITH_ARIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_anon_WITH_ARIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_PSK_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_PSK_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_PSK_WITH_ARIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_PSK_WITH_ARIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384,
|
||||||
|
cipher_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256,
|
||||||
|
cipher_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384,
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_CCM,
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_CCM,
|
||||||
|
cipher_TLS_RSA_WITH_AES_128_CCM_8,
|
||||||
|
cipher_TLS_RSA_WITH_AES_256_CCM_8,
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_CCM,
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_CCM,
|
||||||
|
cipher_TLS_PSK_WITH_AES_128_CCM_8,
|
||||||
|
cipher_TLS_PSK_WITH_AES_256_CCM_8:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
256
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
Normal file
256
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// Transport code's client connection pooling.
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientConnPool manages a pool of HTTP/2 client connections.
|
||||||
|
type ClientConnPool interface {
|
||||||
|
GetClientConn(req *http.Request, addr string) (*ClientConn, error)
|
||||||
|
MarkDead(*ClientConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
|
||||||
|
// implementations which can close their idle connections.
|
||||||
|
type clientConnPoolIdleCloser interface {
|
||||||
|
ClientConnPool
|
||||||
|
closeIdleConnections()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ clientConnPoolIdleCloser = (*clientConnPool)(nil)
|
||||||
|
_ clientConnPoolIdleCloser = noDialClientConnPool{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: use singleflight for dialing and addConnCalls?
|
||||||
|
type clientConnPool struct {
|
||||||
|
t *Transport
|
||||||
|
|
||||||
|
mu sync.Mutex // TODO: maybe switch to RWMutex
|
||||||
|
// TODO: add support for sharing conns based on cert names
|
||||||
|
// (e.g. share conn for googleapis.com and appspot.com)
|
||||||
|
conns map[string][]*ClientConn // key is host:port
|
||||||
|
dialing map[string]*dialCall // currently in-flight dials
|
||||||
|
keys map[*ClientConn][]string
|
||||||
|
addConnCalls map[string]*addConnCall // in-flight addConnIfNeede calls
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *clientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
|
||||||
|
return p.getClientConn(req, addr, dialOnMiss)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
dialOnMiss = true
|
||||||
|
noDialOnMiss = false
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) {
|
||||||
|
if isConnectionCloseRequest(req) && dialOnMiss {
|
||||||
|
// It gets its own connection.
|
||||||
|
const singleUse = true
|
||||||
|
cc, err := p.t.dialClientConn(addr, singleUse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return cc, nil
|
||||||
|
}
|
||||||
|
p.mu.Lock()
|
||||||
|
for _, cc := range p.conns[addr] {
|
||||||
|
if cc.CanTakeNewRequest() {
|
||||||
|
p.mu.Unlock()
|
||||||
|
return cc, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !dialOnMiss {
|
||||||
|
p.mu.Unlock()
|
||||||
|
return nil, ErrNoCachedConn
|
||||||
|
}
|
||||||
|
call := p.getStartDialLocked(addr)
|
||||||
|
p.mu.Unlock()
|
||||||
|
<-call.done
|
||||||
|
return call.res, call.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialCall is an in-flight Transport dial call to a host.
|
||||||
|
type dialCall struct {
|
||||||
|
p *clientConnPool
|
||||||
|
done chan struct{} // closed when done
|
||||||
|
res *ClientConn // valid after done is closed
|
||||||
|
err error // valid after done is closed
|
||||||
|
}
|
||||||
|
|
||||||
|
// requires p.mu is held.
|
||||||
|
func (p *clientConnPool) getStartDialLocked(addr string) *dialCall {
|
||||||
|
if call, ok := p.dialing[addr]; ok {
|
||||||
|
// A dial is already in-flight. Don't start another.
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
call := &dialCall{p: p, done: make(chan struct{})}
|
||||||
|
if p.dialing == nil {
|
||||||
|
p.dialing = make(map[string]*dialCall)
|
||||||
|
}
|
||||||
|
p.dialing[addr] = call
|
||||||
|
go call.dial(addr)
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
|
||||||
|
// run in its own goroutine.
|
||||||
|
func (c *dialCall) dial(addr string) {
|
||||||
|
const singleUse = false // shared conn
|
||||||
|
c.res, c.err = c.p.t.dialClientConn(addr, singleUse)
|
||||||
|
close(c.done)
|
||||||
|
|
||||||
|
c.p.mu.Lock()
|
||||||
|
delete(c.p.dialing, addr)
|
||||||
|
if c.err == nil {
|
||||||
|
c.p.addConnLocked(addr, c.res)
|
||||||
|
}
|
||||||
|
c.p.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't
|
||||||
|
// already exist. It coalesces concurrent calls with the same key.
|
||||||
|
// This is used by the http1 Transport code when it creates a new connection. Because
|
||||||
|
// the http1 Transport doesn't de-dup TCP dials to outbound hosts (because it doesn't know
|
||||||
|
// the protocol), it can get into a situation where it has multiple TLS connections.
|
||||||
|
// This code decides which ones live or die.
|
||||||
|
// The return value used is whether c was used.
|
||||||
|
// c is never closed.
|
||||||
|
func (p *clientConnPool) addConnIfNeeded(key string, t *Transport, c *tls.Conn) (used bool, err error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
for _, cc := range p.conns[key] {
|
||||||
|
if cc.CanTakeNewRequest() {
|
||||||
|
p.mu.Unlock()
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
call, dup := p.addConnCalls[key]
|
||||||
|
if !dup {
|
||||||
|
if p.addConnCalls == nil {
|
||||||
|
p.addConnCalls = make(map[string]*addConnCall)
|
||||||
|
}
|
||||||
|
call = &addConnCall{
|
||||||
|
p: p,
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
p.addConnCalls[key] = call
|
||||||
|
go call.run(t, key, c)
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
|
||||||
|
<-call.done
|
||||||
|
if call.err != nil {
|
||||||
|
return false, call.err
|
||||||
|
}
|
||||||
|
return !dup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type addConnCall struct {
|
||||||
|
p *clientConnPool
|
||||||
|
done chan struct{} // closed when done
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *addConnCall) run(t *Transport, key string, tc *tls.Conn) {
|
||||||
|
cc, err := t.NewClientConn(tc)
|
||||||
|
|
||||||
|
p := c.p
|
||||||
|
p.mu.Lock()
|
||||||
|
if err != nil {
|
||||||
|
c.err = err
|
||||||
|
} else {
|
||||||
|
p.addConnLocked(key, cc)
|
||||||
|
}
|
||||||
|
delete(p.addConnCalls, key)
|
||||||
|
p.mu.Unlock()
|
||||||
|
close(c.done)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *clientConnPool) addConn(key string, cc *ClientConn) {
|
||||||
|
p.mu.Lock()
|
||||||
|
p.addConnLocked(key, cc)
|
||||||
|
p.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// p.mu must be held
|
||||||
|
func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) {
|
||||||
|
for _, v := range p.conns[key] {
|
||||||
|
if v == cc {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.conns == nil {
|
||||||
|
p.conns = make(map[string][]*ClientConn)
|
||||||
|
}
|
||||||
|
if p.keys == nil {
|
||||||
|
p.keys = make(map[*ClientConn][]string)
|
||||||
|
}
|
||||||
|
p.conns[key] = append(p.conns[key], cc)
|
||||||
|
p.keys[cc] = append(p.keys[cc], key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *clientConnPool) MarkDead(cc *ClientConn) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
for _, key := range p.keys[cc] {
|
||||||
|
vv, ok := p.conns[key]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newList := filterOutClientConn(vv, cc)
|
||||||
|
if len(newList) > 0 {
|
||||||
|
p.conns[key] = newList
|
||||||
|
} else {
|
||||||
|
delete(p.conns, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(p.keys, cc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *clientConnPool) closeIdleConnections() {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
// TODO: don't close a cc if it was just added to the pool
|
||||||
|
// milliseconds ago and has never been used. There's currently
|
||||||
|
// a small race window with the HTTP/1 Transport's integration
|
||||||
|
// where it can add an idle conn just before using it, and
|
||||||
|
// somebody else can concurrently call CloseIdleConns and
|
||||||
|
// break some caller's RoundTrip.
|
||||||
|
for _, vv := range p.conns {
|
||||||
|
for _, cc := range vv {
|
||||||
|
cc.closeIfIdle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
|
||||||
|
out := in[:0]
|
||||||
|
for _, v := range in {
|
||||||
|
if v != exclude {
|
||||||
|
out = append(out, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we filtered it out, zero out the last item to prevent
|
||||||
|
// the GC from seeing it.
|
||||||
|
if len(in) != len(out) {
|
||||||
|
in[len(in)-1] = nil
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// noDialClientConnPool is an implementation of http2.ClientConnPool
|
||||||
|
// which never dials. We let the HTTP/1.1 client dial and use its TLS
|
||||||
|
// connection instead.
|
||||||
|
type noDialClientConnPool struct{ *clientConnPool }
|
||||||
|
|
||||||
|
func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
|
||||||
|
return p.getClientConn(req, addr, noDialOnMiss)
|
||||||
|
}
|
80
vendor/golang.org/x/net/http2/configure_transport.go
generated
vendored
Normal file
80
vendor/golang.org/x/net/http2/configure_transport.go
generated
vendored
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// +build go1.6
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func configureTransport(t1 *http.Transport) (*Transport, error) {
|
||||||
|
connPool := new(clientConnPool)
|
||||||
|
t2 := &Transport{
|
||||||
|
ConnPool: noDialClientConnPool{connPool},
|
||||||
|
t1: t1,
|
||||||
|
}
|
||||||
|
connPool.t = t2
|
||||||
|
if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if t1.TLSClientConfig == nil {
|
||||||
|
t1.TLSClientConfig = new(tls.Config)
|
||||||
|
}
|
||||||
|
if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
|
||||||
|
t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
|
||||||
|
}
|
||||||
|
if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
|
||||||
|
t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
|
||||||
|
}
|
||||||
|
upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper {
|
||||||
|
addr := authorityAddr("https", authority)
|
||||||
|
if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
|
||||||
|
go c.Close()
|
||||||
|
return erringRoundTripper{err}
|
||||||
|
} else if !used {
|
||||||
|
// Turns out we don't need this c.
|
||||||
|
// For example, two goroutines made requests to the same host
|
||||||
|
// at the same time, both kicking off TCP dials. (since protocol
|
||||||
|
// was unknown)
|
||||||
|
go c.Close()
|
||||||
|
}
|
||||||
|
return t2
|
||||||
|
}
|
||||||
|
if m := t1.TLSNextProto; len(m) == 0 {
|
||||||
|
t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{
|
||||||
|
"h2": upgradeFn,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m["h2"] = upgradeFn
|
||||||
|
}
|
||||||
|
return t2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerHTTPSProtocol calls Transport.RegisterProtocol but
|
||||||
|
// converting panics into errors.
|
||||||
|
func registerHTTPSProtocol(t *http.Transport, rt http.RoundTripper) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
err = fmt.Errorf("%v", e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
t.RegisterProtocol("https", rt)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
|
||||||
|
// if there's already has a cached connection to the host.
|
||||||
|
type noDialH2RoundTripper struct{ t *Transport }
|
||||||
|
|
||||||
|
func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
res, err := rt.t.RoundTrip(req)
|
||||||
|
if err == ErrNoCachedConn {
|
||||||
|
return nil, http.ErrSkipAltProtocol
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
146
vendor/golang.org/x/net/http2/databuffer.go
generated
vendored
Normal file
146
vendor/golang.org/x/net/http2/databuffer.go
generated
vendored
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
// Copyright 2014 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 http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Buffer chunks are allocated from a pool to reduce pressure on GC.
|
||||||
|
// The maximum wasted space per dataBuffer is 2x the largest size class,
|
||||||
|
// which happens when the dataBuffer has multiple chunks and there is
|
||||||
|
// one unread byte in both the first and last chunks. We use a few size
|
||||||
|
// classes to minimize overheads for servers that typically receive very
|
||||||
|
// small request bodies.
|
||||||
|
//
|
||||||
|
// TODO: Benchmark to determine if the pools are necessary. The GC may have
|
||||||
|
// improved enough that we can instead allocate chunks like this:
|
||||||
|
// make([]byte, max(16<<10, expectedBytesRemaining))
|
||||||
|
var (
|
||||||
|
dataChunkSizeClasses = []int{
|
||||||
|
1 << 10,
|
||||||
|
2 << 10,
|
||||||
|
4 << 10,
|
||||||
|
8 << 10,
|
||||||
|
16 << 10,
|
||||||
|
}
|
||||||
|
dataChunkPools = [...]sync.Pool{
|
||||||
|
{New: func() interface{} { return make([]byte, 1<<10) }},
|
||||||
|
{New: func() interface{} { return make([]byte, 2<<10) }},
|
||||||
|
{New: func() interface{} { return make([]byte, 4<<10) }},
|
||||||
|
{New: func() interface{} { return make([]byte, 8<<10) }},
|
||||||
|
{New: func() interface{} { return make([]byte, 16<<10) }},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDataBufferChunk(size int64) []byte {
|
||||||
|
i := 0
|
||||||
|
for ; i < len(dataChunkSizeClasses)-1; i++ {
|
||||||
|
if size <= int64(dataChunkSizeClasses[i]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataChunkPools[i].Get().([]byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
func putDataBufferChunk(p []byte) {
|
||||||
|
for i, n := range dataChunkSizeClasses {
|
||||||
|
if len(p) == n {
|
||||||
|
dataChunkPools[i].Put(p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataBuffer is an io.ReadWriter backed by a list of data chunks.
|
||||||
|
// Each dataBuffer is used to read DATA frames on a single stream.
|
||||||
|
// The buffer is divided into chunks so the server can limit the
|
||||||
|
// total memory used by a single connection without limiting the
|
||||||
|
// request body size on any single stream.
|
||||||
|
type dataBuffer struct {
|
||||||
|
chunks [][]byte
|
||||||
|
r int // next byte to read is chunks[0][r]
|
||||||
|
w int // next byte to write is chunks[len(chunks)-1][w]
|
||||||
|
size int // total buffered bytes
|
||||||
|
expected int64 // we expect at least this many bytes in future Write calls (ignored if <= 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errReadEmpty = errors.New("read from empty dataBuffer")
|
||||||
|
|
||||||
|
// Read copies bytes from the buffer into p.
|
||||||
|
// It is an error to read when no data is available.
|
||||||
|
func (b *dataBuffer) Read(p []byte) (int, error) {
|
||||||
|
if b.size == 0 {
|
||||||
|
return 0, errReadEmpty
|
||||||
|
}
|
||||||
|
var ntotal int
|
||||||
|
for len(p) > 0 && b.size > 0 {
|
||||||
|
readFrom := b.bytesFromFirstChunk()
|
||||||
|
n := copy(p, readFrom)
|
||||||
|
p = p[n:]
|
||||||
|
ntotal += n
|
||||||
|
b.r += n
|
||||||
|
b.size -= n
|
||||||
|
// If the first chunk has been consumed, advance to the next chunk.
|
||||||
|
if b.r == len(b.chunks[0]) {
|
||||||
|
putDataBufferChunk(b.chunks[0])
|
||||||
|
end := len(b.chunks) - 1
|
||||||
|
copy(b.chunks[:end], b.chunks[1:])
|
||||||
|
b.chunks[end] = nil
|
||||||
|
b.chunks = b.chunks[:end]
|
||||||
|
b.r = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ntotal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *dataBuffer) bytesFromFirstChunk() []byte {
|
||||||
|
if len(b.chunks) == 1 {
|
||||||
|
return b.chunks[0][b.r:b.w]
|
||||||
|
}
|
||||||
|
return b.chunks[0][b.r:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of bytes of the unread portion of the buffer.
|
||||||
|
func (b *dataBuffer) Len() int {
|
||||||
|
return b.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write appends p to the buffer.
|
||||||
|
func (b *dataBuffer) Write(p []byte) (int, error) {
|
||||||
|
ntotal := len(p)
|
||||||
|
for len(p) > 0 {
|
||||||
|
// If the last chunk is empty, allocate a new chunk. Try to allocate
|
||||||
|
// enough to fully copy p plus any additional bytes we expect to
|
||||||
|
// receive. However, this may allocate less than len(p).
|
||||||
|
want := int64(len(p))
|
||||||
|
if b.expected > want {
|
||||||
|
want = b.expected
|
||||||
|
}
|
||||||
|
chunk := b.lastChunkOrAlloc(want)
|
||||||
|
n := copy(chunk[b.w:], p)
|
||||||
|
p = p[n:]
|
||||||
|
b.w += n
|
||||||
|
b.size += n
|
||||||
|
b.expected -= int64(n)
|
||||||
|
}
|
||||||
|
return ntotal, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *dataBuffer) lastChunkOrAlloc(want int64) []byte {
|
||||||
|
if len(b.chunks) != 0 {
|
||||||
|
last := b.chunks[len(b.chunks)-1]
|
||||||
|
if b.w < len(last) {
|
||||||
|
return last
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chunk := getDataBufferChunk(want)
|
||||||
|
b.chunks = append(b.chunks, chunk)
|
||||||
|
b.w = 0
|
||||||
|
return chunk
|
||||||
|
}
|
133
vendor/golang.org/x/net/http2/errors.go
generated
vendored
Normal file
133
vendor/golang.org/x/net/http2/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
// Copyright 2014 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 http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
|
||||||
|
type ErrCode uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
ErrCodeNo ErrCode = 0x0
|
||||||
|
ErrCodeProtocol ErrCode = 0x1
|
||||||
|
ErrCodeInternal ErrCode = 0x2
|
||||||
|
ErrCodeFlowControl ErrCode = 0x3
|
||||||
|
ErrCodeSettingsTimeout ErrCode = 0x4
|
||||||
|
ErrCodeStreamClosed ErrCode = 0x5
|
||||||
|
ErrCodeFrameSize ErrCode = 0x6
|
||||||
|
ErrCodeRefusedStream ErrCode = 0x7
|
||||||
|
ErrCodeCancel ErrCode = 0x8
|
||||||
|
ErrCodeCompression ErrCode = 0x9
|
||||||
|
ErrCodeConnect ErrCode = 0xa
|
||||||
|
ErrCodeEnhanceYourCalm ErrCode = 0xb
|
||||||
|
ErrCodeInadequateSecurity ErrCode = 0xc
|
||||||
|
ErrCodeHTTP11Required ErrCode = 0xd
|
||||||
|
)
|
||||||
|
|
||||||
|
var errCodeName = map[ErrCode]string{
|
||||||
|
ErrCodeNo: "NO_ERROR",
|
||||||
|
ErrCodeProtocol: "PROTOCOL_ERROR",
|
||||||
|
ErrCodeInternal: "INTERNAL_ERROR",
|
||||||
|
ErrCodeFlowControl: "FLOW_CONTROL_ERROR",
|
||||||
|
ErrCodeSettingsTimeout: "SETTINGS_TIMEOUT",
|
||||||
|
ErrCodeStreamClosed: "STREAM_CLOSED",
|
||||||
|
ErrCodeFrameSize: "FRAME_SIZE_ERROR",
|
||||||
|
ErrCodeRefusedStream: "REFUSED_STREAM",
|
||||||
|
ErrCodeCancel: "CANCEL",
|
||||||
|
ErrCodeCompression: "COMPRESSION_ERROR",
|
||||||
|
ErrCodeConnect: "CONNECT_ERROR",
|
||||||
|
ErrCodeEnhanceYourCalm: "ENHANCE_YOUR_CALM",
|
||||||
|
ErrCodeInadequateSecurity: "INADEQUATE_SECURITY",
|
||||||
|
ErrCodeHTTP11Required: "HTTP_1_1_REQUIRED",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrCode) String() string {
|
||||||
|
if s, ok := errCodeName[e]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("unknown error code 0x%x", uint32(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectionError is an error that results in the termination of the
|
||||||
|
// entire connection.
|
||||||
|
type ConnectionError ErrCode
|
||||||
|
|
||||||
|
func (e ConnectionError) Error() string { return fmt.Sprintf("connection error: %s", ErrCode(e)) }
|
||||||
|
|
||||||
|
// StreamError is an error that only affects one stream within an
|
||||||
|
// HTTP/2 connection.
|
||||||
|
type StreamError struct {
|
||||||
|
StreamID uint32
|
||||||
|
Code ErrCode
|
||||||
|
Cause error // optional additional detail
|
||||||
|
}
|
||||||
|
|
||||||
|
func streamError(id uint32, code ErrCode) StreamError {
|
||||||
|
return StreamError{StreamID: id, Code: code}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e StreamError) Error() string {
|
||||||
|
if e.Cause != nil {
|
||||||
|
return fmt.Sprintf("stream error: stream ID %d; %v; %v", e.StreamID, e.Code, e.Cause)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("stream error: stream ID %d; %v", e.StreamID, e.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6.9.1 The Flow Control Window
|
||||||
|
// "If a sender receives a WINDOW_UPDATE that causes a flow control
|
||||||
|
// window to exceed this maximum it MUST terminate either the stream
|
||||||
|
// or the connection, as appropriate. For streams, [...]; for the
|
||||||
|
// connection, a GOAWAY frame with a FLOW_CONTROL_ERROR code."
|
||||||
|
type goAwayFlowError struct{}
|
||||||
|
|
||||||
|
func (goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
|
||||||
|
|
||||||
|
// connError represents an HTTP/2 ConnectionError error code, along
|
||||||
|
// with a string (for debugging) explaining why.
|
||||||
|
//
|
||||||
|
// Errors of this type are only returned by the frame parser functions
|
||||||
|
// and converted into ConnectionError(Code), after stashing away
|
||||||
|
// the Reason into the Framer's errDetail field, accessible via
|
||||||
|
// the (*Framer).ErrorDetail method.
|
||||||
|
type connError struct {
|
||||||
|
Code ErrCode // the ConnectionError error code
|
||||||
|
Reason string // additional reason
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e connError) Error() string {
|
||||||
|
return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pseudoHeaderError string
|
||||||
|
|
||||||
|
func (e pseudoHeaderError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid pseudo-header %q", string(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
type duplicatePseudoHeaderError string
|
||||||
|
|
||||||
|
func (e duplicatePseudoHeaderError) Error() string {
|
||||||
|
return fmt.Sprintf("duplicate pseudo-header %q", string(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerFieldNameError string
|
||||||
|
|
||||||
|
func (e headerFieldNameError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid header field name %q", string(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerFieldValueError string
|
||||||
|
|
||||||
|
func (e headerFieldValueError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid header field value %q", string(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
|
||||||
|
errPseudoAfterRegular = errors.New("pseudo header field after regular")
|
||||||
|
)
|
50
vendor/golang.org/x/net/http2/flow.go
generated
vendored
Normal file
50
vendor/golang.org/x/net/http2/flow.go
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// Flow control
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
// flow is the flow control window's size.
|
||||||
|
type flow struct {
|
||||||
|
// n is the number of DATA bytes we're allowed to send.
|
||||||
|
// A flow is kept both on a conn and a per-stream.
|
||||||
|
n int32
|
||||||
|
|
||||||
|
// conn points to the shared connection-level flow that is
|
||||||
|
// shared by all streams on that conn. It is nil for the flow
|
||||||
|
// that's on the conn directly.
|
||||||
|
conn *flow
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *flow) setConnFlow(cf *flow) { f.conn = cf }
|
||||||
|
|
||||||
|
func (f *flow) available() int32 {
|
||||||
|
n := f.n
|
||||||
|
if f.conn != nil && f.conn.n < n {
|
||||||
|
n = f.conn.n
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *flow) take(n int32) {
|
||||||
|
if n > f.available() {
|
||||||
|
panic("internal error: took too much")
|
||||||
|
}
|
||||||
|
f.n -= n
|
||||||
|
if f.conn != nil {
|
||||||
|
f.conn.n -= n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add adds n bytes (positive or negative) to the flow control window.
|
||||||
|
// It returns false if the sum would exceed 2^31-1.
|
||||||
|
func (f *flow) add(n int32) bool {
|
||||||
|
remain := (1<<31 - 1) - f.n
|
||||||
|
if n > remain {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
f.n += n
|
||||||
|
return true
|
||||||
|
}
|
1579
vendor/golang.org/x/net/http2/frame.go
generated
vendored
Normal file
1579
vendor/golang.org/x/net/http2/frame.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
16
vendor/golang.org/x/net/http2/go16.go
generated
vendored
Normal file
16
vendor/golang.org/x/net/http2/go16.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// +build go1.6
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
|
||||||
|
return t1.ExpectContinueTimeout
|
||||||
|
}
|
106
vendor/golang.org/x/net/http2/go17.go
generated
vendored
Normal file
106
vendor/golang.org/x/net/http2/go17.go
generated
vendored
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptrace"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type contextContext interface {
|
||||||
|
context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx contextContext, cancel func()) {
|
||||||
|
ctx, cancel = context.WithCancel(context.Background())
|
||||||
|
ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
|
||||||
|
if hs := opts.baseConfig(); hs != nil {
|
||||||
|
ctx = context.WithValue(ctx, http.ServerContextKey, hs)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextWithCancel(ctx contextContext) (_ contextContext, cancel func()) {
|
||||||
|
return context.WithCancel(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestWithContext(req *http.Request, ctx contextContext) *http.Request {
|
||||||
|
return req.WithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientTrace httptrace.ClientTrace
|
||||||
|
|
||||||
|
func reqContext(r *http.Request) context.Context { return r.Context() }
|
||||||
|
|
||||||
|
func (t *Transport) idleConnTimeout() time.Duration {
|
||||||
|
if t.t1 != nil {
|
||||||
|
return t.t1.IdleConnTimeout
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func setResponseUncompressed(res *http.Response) { res.Uncompressed = true }
|
||||||
|
|
||||||
|
func traceGotConn(req *http.Request, cc *ClientConn) {
|
||||||
|
trace := httptrace.ContextClientTrace(req.Context())
|
||||||
|
if trace == nil || trace.GotConn == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ci := httptrace.GotConnInfo{Conn: cc.tconn}
|
||||||
|
cc.mu.Lock()
|
||||||
|
ci.Reused = cc.nextStreamID > 1
|
||||||
|
ci.WasIdle = len(cc.streams) == 0 && ci.Reused
|
||||||
|
if ci.WasIdle && !cc.lastActive.IsZero() {
|
||||||
|
ci.IdleTime = time.Now().Sub(cc.lastActive)
|
||||||
|
}
|
||||||
|
cc.mu.Unlock()
|
||||||
|
|
||||||
|
trace.GotConn(ci)
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceWroteHeaders(trace *clientTrace) {
|
||||||
|
if trace != nil && trace.WroteHeaders != nil {
|
||||||
|
trace.WroteHeaders()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceGot100Continue(trace *clientTrace) {
|
||||||
|
if trace != nil && trace.Got100Continue != nil {
|
||||||
|
trace.Got100Continue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceWait100Continue(trace *clientTrace) {
|
||||||
|
if trace != nil && trace.Wait100Continue != nil {
|
||||||
|
trace.Wait100Continue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceWroteRequest(trace *clientTrace, err error) {
|
||||||
|
if trace != nil && trace.WroteRequest != nil {
|
||||||
|
trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func traceFirstResponseByte(trace *clientTrace) {
|
||||||
|
if trace != nil && trace.GotFirstResponseByte != nil {
|
||||||
|
trace.GotFirstResponseByte()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestTrace(req *http.Request) *clientTrace {
|
||||||
|
trace := httptrace.ContextClientTrace(req.Context())
|
||||||
|
return (*clientTrace)(trace)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping sends a PING frame to the server and waits for the ack.
|
||||||
|
func (cc *ClientConn) Ping(ctx context.Context) error {
|
||||||
|
return cc.ping(ctx)
|
||||||
|
}
|
36
vendor/golang.org/x/net/http2/go17_not18.go
generated
vendored
Normal file
36
vendor/golang.org/x/net/http2/go17_not18.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// +build go1.7,!go1.8
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import "crypto/tls"
|
||||||
|
|
||||||
|
// temporary copy of Go 1.7's private tls.Config.clone:
|
||||||
|
func cloneTLSConfig(c *tls.Config) *tls.Config {
|
||||||
|
return &tls.Config{
|
||||||
|
Rand: c.Rand,
|
||||||
|
Time: c.Time,
|
||||||
|
Certificates: c.Certificates,
|
||||||
|
NameToCertificate: c.NameToCertificate,
|
||||||
|
GetCertificate: c.GetCertificate,
|
||||||
|
RootCAs: c.RootCAs,
|
||||||
|
NextProtos: c.NextProtos,
|
||||||
|
ServerName: c.ServerName,
|
||||||
|
ClientAuth: c.ClientAuth,
|
||||||
|
ClientCAs: c.ClientCAs,
|
||||||
|
InsecureSkipVerify: c.InsecureSkipVerify,
|
||||||
|
CipherSuites: c.CipherSuites,
|
||||||
|
PreferServerCipherSuites: c.PreferServerCipherSuites,
|
||||||
|
SessionTicketsDisabled: c.SessionTicketsDisabled,
|
||||||
|
SessionTicketKey: c.SessionTicketKey,
|
||||||
|
ClientSessionCache: c.ClientSessionCache,
|
||||||
|
MinVersion: c.MinVersion,
|
||||||
|
MaxVersion: c.MaxVersion,
|
||||||
|
CurvePreferences: c.CurvePreferences,
|
||||||
|
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
|
||||||
|
Renegotiation: c.Renegotiation,
|
||||||
|
}
|
||||||
|
}
|
56
vendor/golang.org/x/net/http2/go18.go
generated
vendored
Normal file
56
vendor/golang.org/x/net/http2/go18.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// +build go1.8
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cloneTLSConfig(c *tls.Config) *tls.Config {
|
||||||
|
c2 := c.Clone()
|
||||||
|
c2.GetClientCertificate = c.GetClientCertificate // golang.org/issue/19264
|
||||||
|
return c2
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ http.Pusher = (*responseWriter)(nil)
|
||||||
|
|
||||||
|
// Push implements http.Pusher.
|
||||||
|
func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
|
||||||
|
internalOpts := pushOptions{}
|
||||||
|
if opts != nil {
|
||||||
|
internalOpts.Method = opts.Method
|
||||||
|
internalOpts.Header = opts.Header
|
||||||
|
}
|
||||||
|
return w.push(target, internalOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureServer18(h1 *http.Server, h2 *Server) error {
|
||||||
|
if h2.IdleTimeout == 0 {
|
||||||
|
if h1.IdleTimeout != 0 {
|
||||||
|
h2.IdleTimeout = h1.IdleTimeout
|
||||||
|
} else {
|
||||||
|
h2.IdleTimeout = h1.ReadTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldLogPanic(panicValue interface{}) bool {
|
||||||
|
return panicValue != nil && panicValue != http.ErrAbortHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func reqGetBody(req *http.Request) func() (io.ReadCloser, error) {
|
||||||
|
return req.GetBody
|
||||||
|
}
|
||||||
|
|
||||||
|
func reqBodyIsNoBody(body io.ReadCloser) bool {
|
||||||
|
return body == http.NoBody
|
||||||
|
}
|
||||||
|
|
||||||
|
func go18httpNoBody() io.ReadCloser { return http.NoBody } // for tests only
|
16
vendor/golang.org/x/net/http2/go19.go
generated
vendored
Normal file
16
vendor/golang.org/x/net/http2/go19.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func configureServer19(s *http.Server, conf *Server) error {
|
||||||
|
s.RegisterOnShutdown(conf.state.startGracefulShutdown)
|
||||||
|
return nil
|
||||||
|
}
|
170
vendor/golang.org/x/net/http2/gotrack.go
generated
vendored
Normal file
170
vendor/golang.org/x/net/http2/gotrack.go
generated
vendored
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright 2014 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.
|
||||||
|
|
||||||
|
// Defensive debug-only utility to track that functions run on the
|
||||||
|
// goroutine that they're supposed to.
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
|
||||||
|
|
||||||
|
type goroutineLock uint64
|
||||||
|
|
||||||
|
func newGoroutineLock() goroutineLock {
|
||||||
|
if !DebugGoroutines {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return goroutineLock(curGoroutineID())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g goroutineLock) check() {
|
||||||
|
if !DebugGoroutines {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if curGoroutineID() != uint64(g) {
|
||||||
|
panic("running on the wrong goroutine")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g goroutineLock) checkNotOn() {
|
||||||
|
if !DebugGoroutines {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if curGoroutineID() == uint64(g) {
|
||||||
|
panic("running on the wrong goroutine")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var goroutineSpace = []byte("goroutine ")
|
||||||
|
|
||||||
|
func curGoroutineID() uint64 {
|
||||||
|
bp := littleBuf.Get().(*[]byte)
|
||||||
|
defer littleBuf.Put(bp)
|
||||||
|
b := *bp
|
||||||
|
b = b[:runtime.Stack(b, false)]
|
||||||
|
// Parse the 4707 out of "goroutine 4707 ["
|
||||||
|
b = bytes.TrimPrefix(b, goroutineSpace)
|
||||||
|
i := bytes.IndexByte(b, ' ')
|
||||||
|
if i < 0 {
|
||||||
|
panic(fmt.Sprintf("No space found in %q", b))
|
||||||
|
}
|
||||||
|
b = b[:i]
|
||||||
|
n, err := parseUintBytes(b, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to parse goroutine ID out of %q: %v", b, err))
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
var littleBuf = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
buf := make([]byte, 64)
|
||||||
|
return &buf
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseUintBytes is like strconv.ParseUint, but using a []byte.
|
||||||
|
func parseUintBytes(s []byte, base int, bitSize int) (n uint64, err error) {
|
||||||
|
var cutoff, maxVal uint64
|
||||||
|
|
||||||
|
if bitSize == 0 {
|
||||||
|
bitSize = int(strconv.IntSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
s0 := s
|
||||||
|
switch {
|
||||||
|
case len(s) < 1:
|
||||||
|
err = strconv.ErrSyntax
|
||||||
|
goto Error
|
||||||
|
|
||||||
|
case 2 <= base && base <= 36:
|
||||||
|
// valid base; nothing to do
|
||||||
|
|
||||||
|
case base == 0:
|
||||||
|
// Look for octal, hex prefix.
|
||||||
|
switch {
|
||||||
|
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
|
||||||
|
base = 16
|
||||||
|
s = s[2:]
|
||||||
|
if len(s) < 1 {
|
||||||
|
err = strconv.ErrSyntax
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
case s[0] == '0':
|
||||||
|
base = 8
|
||||||
|
default:
|
||||||
|
base = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = errors.New("invalid base " + strconv.Itoa(base))
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
cutoff = cutoff64(base)
|
||||||
|
maxVal = 1<<uint(bitSize) - 1
|
||||||
|
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
var v byte
|
||||||
|
d := s[i]
|
||||||
|
switch {
|
||||||
|
case '0' <= d && d <= '9':
|
||||||
|
v = d - '0'
|
||||||
|
case 'a' <= d && d <= 'z':
|
||||||
|
v = d - 'a' + 10
|
||||||
|
case 'A' <= d && d <= 'Z':
|
||||||
|
v = d - 'A' + 10
|
||||||
|
default:
|
||||||
|
n = 0
|
||||||
|
err = strconv.ErrSyntax
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
if int(v) >= base {
|
||||||
|
n = 0
|
||||||
|
err = strconv.ErrSyntax
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if n >= cutoff {
|
||||||
|
// n*base overflows
|
||||||
|
n = 1<<64 - 1
|
||||||
|
err = strconv.ErrRange
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
n *= uint64(base)
|
||||||
|
|
||||||
|
n1 := n + uint64(v)
|
||||||
|
if n1 < n || n1 > maxVal {
|
||||||
|
// n+v overflows
|
||||||
|
n = 1<<64 - 1
|
||||||
|
err = strconv.ErrRange
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
n = n1
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
|
||||||
|
Error:
|
||||||
|
return n, &strconv.NumError{Func: "ParseUint", Num: string(s0), Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the first number n such that n*base >= 1<<64.
|
||||||
|
func cutoff64(base int) uint64 {
|
||||||
|
if base < 2 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (1<<64-1)/uint64(base) + 1
|
||||||
|
}
|
78
vendor/golang.org/x/net/http2/headermap.go
generated
vendored
Normal file
78
vendor/golang.org/x/net/http2/headermap.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
// Copyright 2014 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 http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
commonLowerHeader = map[string]string{} // Go-Canonical-Case -> lower-case
|
||||||
|
commonCanonHeader = map[string]string{} // lower-case -> Go-Canonical-Case
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for _, v := range []string{
|
||||||
|
"accept",
|
||||||
|
"accept-charset",
|
||||||
|
"accept-encoding",
|
||||||
|
"accept-language",
|
||||||
|
"accept-ranges",
|
||||||
|
"age",
|
||||||
|
"access-control-allow-origin",
|
||||||
|
"allow",
|
||||||
|
"authorization",
|
||||||
|
"cache-control",
|
||||||
|
"content-disposition",
|
||||||
|
"content-encoding",
|
||||||
|
"content-language",
|
||||||
|
"content-length",
|
||||||
|
"content-location",
|
||||||
|
"content-range",
|
||||||
|
"content-type",
|
||||||
|
"cookie",
|
||||||
|
"date",
|
||||||
|
"etag",
|
||||||
|
"expect",
|
||||||
|
"expires",
|
||||||
|
"from",
|
||||||
|
"host",
|
||||||
|
"if-match",
|
||||||
|
"if-modified-since",
|
||||||
|
"if-none-match",
|
||||||
|
"if-unmodified-since",
|
||||||
|
"last-modified",
|
||||||
|
"link",
|
||||||
|
"location",
|
||||||
|
"max-forwards",
|
||||||
|
"proxy-authenticate",
|
||||||
|
"proxy-authorization",
|
||||||
|
"range",
|
||||||
|
"referer",
|
||||||
|
"refresh",
|
||||||
|
"retry-after",
|
||||||
|
"server",
|
||||||
|
"set-cookie",
|
||||||
|
"strict-transport-security",
|
||||||
|
"trailer",
|
||||||
|
"transfer-encoding",
|
||||||
|
"user-agent",
|
||||||
|
"vary",
|
||||||
|
"via",
|
||||||
|
"www-authenticate",
|
||||||
|
} {
|
||||||
|
chk := http.CanonicalHeaderKey(v)
|
||||||
|
commonLowerHeader[chk] = v
|
||||||
|
commonCanonHeader[v] = chk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lowerHeader(v string) string {
|
||||||
|
if s, ok := commonLowerHeader[v]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return strings.ToLower(v)
|
||||||
|
}
|
240
vendor/golang.org/x/net/http2/hpack/encode.go
generated
vendored
Normal file
240
vendor/golang.org/x/net/http2/hpack/encode.go
generated
vendored
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
// Copyright 2014 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 hpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
uint32Max = ^uint32(0)
|
||||||
|
initialHeaderTableSize = 4096
|
||||||
|
)
|
||||||
|
|
||||||
|
type Encoder struct {
|
||||||
|
dynTab dynamicTable
|
||||||
|
// minSize is the minimum table size set by
|
||||||
|
// SetMaxDynamicTableSize after the previous Header Table Size
|
||||||
|
// Update.
|
||||||
|
minSize uint32
|
||||||
|
// maxSizeLimit is the maximum table size this encoder
|
||||||
|
// supports. This will protect the encoder from too large
|
||||||
|
// size.
|
||||||
|
maxSizeLimit uint32
|
||||||
|
// tableSizeUpdate indicates whether "Header Table Size
|
||||||
|
// Update" is required.
|
||||||
|
tableSizeUpdate bool
|
||||||
|
w io.Writer
|
||||||
|
buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns a new Encoder which performs HPACK encoding. An
|
||||||
|
// encoded data is written to w.
|
||||||
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
|
e := &Encoder{
|
||||||
|
minSize: uint32Max,
|
||||||
|
maxSizeLimit: initialHeaderTableSize,
|
||||||
|
tableSizeUpdate: false,
|
||||||
|
w: w,
|
||||||
|
}
|
||||||
|
e.dynTab.table.init()
|
||||||
|
e.dynTab.setMaxSize(initialHeaderTableSize)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteField encodes f into a single Write to e's underlying Writer.
|
||||||
|
// This function may also produce bytes for "Header Table Size Update"
|
||||||
|
// if necessary. If produced, it is done before encoding f.
|
||||||
|
func (e *Encoder) WriteField(f HeaderField) error {
|
||||||
|
e.buf = e.buf[:0]
|
||||||
|
|
||||||
|
if e.tableSizeUpdate {
|
||||||
|
e.tableSizeUpdate = false
|
||||||
|
if e.minSize < e.dynTab.maxSize {
|
||||||
|
e.buf = appendTableSize(e.buf, e.minSize)
|
||||||
|
}
|
||||||
|
e.minSize = uint32Max
|
||||||
|
e.buf = appendTableSize(e.buf, e.dynTab.maxSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
idx, nameValueMatch := e.searchTable(f)
|
||||||
|
if nameValueMatch {
|
||||||
|
e.buf = appendIndexed(e.buf, idx)
|
||||||
|
} else {
|
||||||
|
indexing := e.shouldIndex(f)
|
||||||
|
if indexing {
|
||||||
|
e.dynTab.add(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
e.buf = appendNewName(e.buf, f, indexing)
|
||||||
|
} else {
|
||||||
|
e.buf = appendIndexedName(e.buf, f, idx, indexing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n, err := e.w.Write(e.buf)
|
||||||
|
if err == nil && n != len(e.buf) {
|
||||||
|
err = io.ErrShortWrite
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// searchTable searches f in both stable and dynamic header tables.
|
||||||
|
// The static header table is searched first. Only when there is no
|
||||||
|
// exact match for both name and value, the dynamic header table is
|
||||||
|
// then searched. If there is no match, i is 0. If both name and value
|
||||||
|
// match, i is the matched index and nameValueMatch becomes true. If
|
||||||
|
// only name matches, i points to that index and nameValueMatch
|
||||||
|
// becomes false.
|
||||||
|
func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
|
||||||
|
i, nameValueMatch = staticTable.search(f)
|
||||||
|
if nameValueMatch {
|
||||||
|
return i, true
|
||||||
|
}
|
||||||
|
|
||||||
|
j, nameValueMatch := e.dynTab.table.search(f)
|
||||||
|
if nameValueMatch || (i == 0 && j != 0) {
|
||||||
|
return j + uint64(staticTable.len()), nameValueMatch
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxDynamicTableSize changes the dynamic header table size to v.
|
||||||
|
// The actual size is bounded by the value passed to
|
||||||
|
// SetMaxDynamicTableSizeLimit.
|
||||||
|
func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
|
||||||
|
if v > e.maxSizeLimit {
|
||||||
|
v = e.maxSizeLimit
|
||||||
|
}
|
||||||
|
if v < e.minSize {
|
||||||
|
e.minSize = v
|
||||||
|
}
|
||||||
|
e.tableSizeUpdate = true
|
||||||
|
e.dynTab.setMaxSize(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMaxDynamicTableSizeLimit changes the maximum value that can be
|
||||||
|
// specified in SetMaxDynamicTableSize to v. By default, it is set to
|
||||||
|
// 4096, which is the same size of the default dynamic header table
|
||||||
|
// size described in HPACK specification. If the current maximum
|
||||||
|
// dynamic header table size is strictly greater than v, "Header Table
|
||||||
|
// Size Update" will be done in the next WriteField call and the
|
||||||
|
// maximum dynamic header table size is truncated to v.
|
||||||
|
func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
|
||||||
|
e.maxSizeLimit = v
|
||||||
|
if e.dynTab.maxSize > v {
|
||||||
|
e.tableSizeUpdate = true
|
||||||
|
e.dynTab.setMaxSize(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldIndex reports whether f should be indexed.
|
||||||
|
func (e *Encoder) shouldIndex(f HeaderField) bool {
|
||||||
|
return !f.Sensitive && f.Size() <= e.dynTab.maxSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendIndexed appends index i, as encoded in "Indexed Header Field"
|
||||||
|
// representation, to dst and returns the extended buffer.
|
||||||
|
func appendIndexed(dst []byte, i uint64) []byte {
|
||||||
|
first := len(dst)
|
||||||
|
dst = appendVarInt(dst, 7, i)
|
||||||
|
dst[first] |= 0x80
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendNewName appends f, as encoded in one of "Literal Header field
|
||||||
|
// - New Name" representation variants, to dst and returns the
|
||||||
|
// extended buffer.
|
||||||
|
//
|
||||||
|
// If f.Sensitive is true, "Never Indexed" representation is used. If
|
||||||
|
// f.Sensitive is false and indexing is true, "Inremental Indexing"
|
||||||
|
// representation is used.
|
||||||
|
func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
|
||||||
|
dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
|
||||||
|
dst = appendHpackString(dst, f.Name)
|
||||||
|
return appendHpackString(dst, f.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendIndexedName appends f and index i referring indexed name
|
||||||
|
// entry, as encoded in one of "Literal Header field - Indexed Name"
|
||||||
|
// representation variants, to dst and returns the extended buffer.
|
||||||
|
//
|
||||||
|
// If f.Sensitive is true, "Never Indexed" representation is used. If
|
||||||
|
// f.Sensitive is false and indexing is true, "Incremental Indexing"
|
||||||
|
// representation is used.
|
||||||
|
func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte {
|
||||||
|
first := len(dst)
|
||||||
|
var n byte
|
||||||
|
if indexing {
|
||||||
|
n = 6
|
||||||
|
} else {
|
||||||
|
n = 4
|
||||||
|
}
|
||||||
|
dst = appendVarInt(dst, n, i)
|
||||||
|
dst[first] |= encodeTypeByte(indexing, f.Sensitive)
|
||||||
|
return appendHpackString(dst, f.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendTableSize appends v, as encoded in "Header Table Size Update"
|
||||||
|
// representation, to dst and returns the extended buffer.
|
||||||
|
func appendTableSize(dst []byte, v uint32) []byte {
|
||||||
|
first := len(dst)
|
||||||
|
dst = appendVarInt(dst, 5, uint64(v))
|
||||||
|
dst[first] |= 0x20
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendVarInt appends i, as encoded in variable integer form using n
|
||||||
|
// bit prefix, to dst and returns the extended buffer.
|
||||||
|
//
|
||||||
|
// See
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#integer.representation
|
||||||
|
func appendVarInt(dst []byte, n byte, i uint64) []byte {
|
||||||
|
k := uint64((1 << n) - 1)
|
||||||
|
if i < k {
|
||||||
|
return append(dst, byte(i))
|
||||||
|
}
|
||||||
|
dst = append(dst, byte(k))
|
||||||
|
i -= k
|
||||||
|
for ; i >= 128; i >>= 7 {
|
||||||
|
dst = append(dst, byte(0x80|(i&0x7f)))
|
||||||
|
}
|
||||||
|
return append(dst, byte(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendHpackString appends s, as encoded in "String Literal"
|
||||||
|
// representation, to dst and returns the the extended buffer.
|
||||||
|
//
|
||||||
|
// s will be encoded in Huffman codes only when it produces strictly
|
||||||
|
// shorter byte string.
|
||||||
|
func appendHpackString(dst []byte, s string) []byte {
|
||||||
|
huffmanLength := HuffmanEncodeLength(s)
|
||||||
|
if huffmanLength < uint64(len(s)) {
|
||||||
|
first := len(dst)
|
||||||
|
dst = appendVarInt(dst, 7, huffmanLength)
|
||||||
|
dst = AppendHuffmanString(dst, s)
|
||||||
|
dst[first] |= 0x80
|
||||||
|
} else {
|
||||||
|
dst = appendVarInt(dst, 7, uint64(len(s)))
|
||||||
|
dst = append(dst, s...)
|
||||||
|
}
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeTypeByte returns type byte. If sensitive is true, type byte
|
||||||
|
// for "Never Indexed" representation is returned. If sensitive is
|
||||||
|
// false and indexing is true, type byte for "Incremental Indexing"
|
||||||
|
// representation is returned. Otherwise, type byte for "Without
|
||||||
|
// Indexing" is returned.
|
||||||
|
func encodeTypeByte(indexing, sensitive bool) byte {
|
||||||
|
if sensitive {
|
||||||
|
return 0x10
|
||||||
|
}
|
||||||
|
if indexing {
|
||||||
|
return 0x40
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
490
vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
Normal file
490
vendor/golang.org/x/net/http2/hpack/hpack.go
generated
vendored
Normal file
|
@ -0,0 +1,490 @@
|
||||||
|
// Copyright 2014 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 hpack implements HPACK, a compression format for
|
||||||
|
// efficiently representing HTTP header fields in the context of HTTP/2.
|
||||||
|
//
|
||||||
|
// See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
|
||||||
|
package hpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A DecodingError is something the spec defines as a decoding error.
|
||||||
|
type DecodingError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (de DecodingError) Error() string {
|
||||||
|
return fmt.Sprintf("decoding error: %v", de.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An InvalidIndexError is returned when an encoder references a table
|
||||||
|
// entry before the static table or after the end of the dynamic table.
|
||||||
|
type InvalidIndexError int
|
||||||
|
|
||||||
|
func (e InvalidIndexError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid indexed representation index %d", int(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A HeaderField is a name-value pair. Both the name and value are
|
||||||
|
// treated as opaque sequences of octets.
|
||||||
|
type HeaderField struct {
|
||||||
|
Name, Value string
|
||||||
|
|
||||||
|
// Sensitive means that this header field should never be
|
||||||
|
// indexed.
|
||||||
|
Sensitive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPseudo reports whether the header field is an http2 pseudo header.
|
||||||
|
// That is, it reports whether it starts with a colon.
|
||||||
|
// It is not otherwise guaranteed to be a valid pseudo header field,
|
||||||
|
// though.
|
||||||
|
func (hf HeaderField) IsPseudo() bool {
|
||||||
|
return len(hf.Name) != 0 && hf.Name[0] == ':'
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hf HeaderField) String() string {
|
||||||
|
var suffix string
|
||||||
|
if hf.Sensitive {
|
||||||
|
suffix = " (sensitive)"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of an entry per RFC 7541 section 4.1.
|
||||||
|
func (hf HeaderField) Size() uint32 {
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
|
||||||
|
// "The size of the dynamic table is the sum of the size of
|
||||||
|
// its entries. The size of an entry is the sum of its name's
|
||||||
|
// length in octets (as defined in Section 5.2), its value's
|
||||||
|
// length in octets (see Section 5.2), plus 32. The size of
|
||||||
|
// an entry is calculated using the length of the name and
|
||||||
|
// value without any Huffman encoding applied."
|
||||||
|
|
||||||
|
// This can overflow if somebody makes a large HeaderField
|
||||||
|
// Name and/or Value by hand, but we don't care, because that
|
||||||
|
// won't happen on the wire because the encoding doesn't allow
|
||||||
|
// it.
|
||||||
|
return uint32(len(hf.Name) + len(hf.Value) + 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Decoder is the decoding context for incremental processing of
|
||||||
|
// header blocks.
|
||||||
|
type Decoder struct {
|
||||||
|
dynTab dynamicTable
|
||||||
|
emit func(f HeaderField)
|
||||||
|
|
||||||
|
emitEnabled bool // whether calls to emit are enabled
|
||||||
|
maxStrLen int // 0 means unlimited
|
||||||
|
|
||||||
|
// buf is the unparsed buffer. It's only written to
|
||||||
|
// saveBuf if it was truncated in the middle of a header
|
||||||
|
// block. Because it's usually not owned, we can only
|
||||||
|
// process it under Write.
|
||||||
|
buf []byte // not owned; only valid during Write
|
||||||
|
|
||||||
|
// saveBuf is previous data passed to Write which we weren't able
|
||||||
|
// to fully parse before. Unlike buf, we own this data.
|
||||||
|
saveBuf bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDecoder returns a new decoder with the provided maximum dynamic
|
||||||
|
// table size. The emitFunc will be called for each valid field
|
||||||
|
// parsed, in the same goroutine as calls to Write, before Write returns.
|
||||||
|
func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder {
|
||||||
|
d := &Decoder{
|
||||||
|
emit: emitFunc,
|
||||||
|
emitEnabled: true,
|
||||||
|
}
|
||||||
|
d.dynTab.table.init()
|
||||||
|
d.dynTab.allowedMaxSize = maxDynamicTableSize
|
||||||
|
d.dynTab.setMaxSize(maxDynamicTableSize)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrStringLength is returned by Decoder.Write when the max string length
|
||||||
|
// (as configured by Decoder.SetMaxStringLength) would be violated.
|
||||||
|
var ErrStringLength = errors.New("hpack: string too long")
|
||||||
|
|
||||||
|
// SetMaxStringLength sets the maximum size of a HeaderField name or
|
||||||
|
// value string. If a string exceeds this length (even after any
|
||||||
|
// decompression), Write will return ErrStringLength.
|
||||||
|
// A value of 0 means unlimited and is the default from NewDecoder.
|
||||||
|
func (d *Decoder) SetMaxStringLength(n int) {
|
||||||
|
d.maxStrLen = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEmitFunc changes the callback used when new header fields
|
||||||
|
// are decoded.
|
||||||
|
// It must be non-nil. It does not affect EmitEnabled.
|
||||||
|
func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) {
|
||||||
|
d.emit = emitFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEmitEnabled controls whether the emitFunc provided to NewDecoder
|
||||||
|
// should be called. The default is true.
|
||||||
|
//
|
||||||
|
// This facility exists to let servers enforce MAX_HEADER_LIST_SIZE
|
||||||
|
// while still decoding and keeping in-sync with decoder state, but
|
||||||
|
// without doing unnecessary decompression or generating unnecessary
|
||||||
|
// garbage for header fields past the limit.
|
||||||
|
func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v }
|
||||||
|
|
||||||
|
// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder
|
||||||
|
// are currently enabled. The default is true.
|
||||||
|
func (d *Decoder) EmitEnabled() bool { return d.emitEnabled }
|
||||||
|
|
||||||
|
// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
|
||||||
|
// underlying buffers for garbage reasons.
|
||||||
|
|
||||||
|
func (d *Decoder) SetMaxDynamicTableSize(v uint32) {
|
||||||
|
d.dynTab.setMaxSize(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAllowedMaxDynamicTableSize sets the upper bound that the encoded
|
||||||
|
// stream (via dynamic table size updates) may set the maximum size
|
||||||
|
// to.
|
||||||
|
func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
|
||||||
|
d.dynTab.allowedMaxSize = v
|
||||||
|
}
|
||||||
|
|
||||||
|
type dynamicTable struct {
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2
|
||||||
|
table headerFieldTable
|
||||||
|
size uint32 // in bytes
|
||||||
|
maxSize uint32 // current maxSize
|
||||||
|
allowedMaxSize uint32 // maxSize may go up to this, inclusive
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dt *dynamicTable) setMaxSize(v uint32) {
|
||||||
|
dt.maxSize = v
|
||||||
|
dt.evict()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dt *dynamicTable) add(f HeaderField) {
|
||||||
|
dt.table.addEntry(f)
|
||||||
|
dt.size += f.Size()
|
||||||
|
dt.evict()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're too big, evict old stuff.
|
||||||
|
func (dt *dynamicTable) evict() {
|
||||||
|
var n int
|
||||||
|
for dt.size > dt.maxSize && n < dt.table.len() {
|
||||||
|
dt.size -= dt.table.ents[n].Size()
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
dt.table.evictOldest(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) maxTableIndex() int {
|
||||||
|
// This should never overflow. RFC 7540 Section 6.5.2 limits the size of
|
||||||
|
// the dynamic table to 2^32 bytes, where each entry will occupy more than
|
||||||
|
// one byte. Further, the staticTable has a fixed, small length.
|
||||||
|
return d.dynTab.table.len() + staticTable.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
|
||||||
|
// See Section 2.3.3.
|
||||||
|
if i == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if i <= uint64(staticTable.len()) {
|
||||||
|
return staticTable.ents[i-1], true
|
||||||
|
}
|
||||||
|
if i > uint64(d.maxTableIndex()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// In the dynamic table, newer entries have lower indices.
|
||||||
|
// However, dt.ents[0] is the oldest entry. Hence, dt.ents is
|
||||||
|
// the reversed dynamic table.
|
||||||
|
dt := d.dynTab.table
|
||||||
|
return dt.ents[dt.len()-(int(i)-staticTable.len())], true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode decodes an entire block.
|
||||||
|
//
|
||||||
|
// TODO: remove this method and make it incremental later? This is
|
||||||
|
// easier for debugging now.
|
||||||
|
func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
|
||||||
|
var hf []HeaderField
|
||||||
|
saveFunc := d.emit
|
||||||
|
defer func() { d.emit = saveFunc }()
|
||||||
|
d.emit = func(f HeaderField) { hf = append(hf, f) }
|
||||||
|
if _, err := d.Write(p); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := d.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return hf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Close() error {
|
||||||
|
if d.saveBuf.Len() > 0 {
|
||||||
|
d.saveBuf.Reset()
|
||||||
|
return DecodingError{errors.New("truncated headers")}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Write(p []byte) (n int, err error) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
// Prevent state machine CPU attacks (making us redo
|
||||||
|
// work up to the point of finding out we don't have
|
||||||
|
// enough data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Only copy the data if we have to. Optimistically assume
|
||||||
|
// that p will contain a complete header block.
|
||||||
|
if d.saveBuf.Len() == 0 {
|
||||||
|
d.buf = p
|
||||||
|
} else {
|
||||||
|
d.saveBuf.Write(p)
|
||||||
|
d.buf = d.saveBuf.Bytes()
|
||||||
|
d.saveBuf.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
for len(d.buf) > 0 {
|
||||||
|
err = d.parseHeaderFieldRepr()
|
||||||
|
if err == errNeedMore {
|
||||||
|
// Extra paranoia, making sure saveBuf won't
|
||||||
|
// get too large. All the varint and string
|
||||||
|
// reading code earlier should already catch
|
||||||
|
// overlong things and return ErrStringLength,
|
||||||
|
// but keep this as a last resort.
|
||||||
|
const varIntOverhead = 8 // conservative
|
||||||
|
if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
|
||||||
|
return 0, ErrStringLength
|
||||||
|
}
|
||||||
|
d.saveBuf.Write(d.buf)
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(p), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// errNeedMore is an internal sentinel error value that means the
|
||||||
|
// buffer is truncated and we need to read more data before we can
|
||||||
|
// continue parsing.
|
||||||
|
var errNeedMore = errors.New("need more data")
|
||||||
|
|
||||||
|
type indexType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
indexedTrue indexType = iota
|
||||||
|
indexedFalse
|
||||||
|
indexedNever
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v indexType) indexed() bool { return v == indexedTrue }
|
||||||
|
func (v indexType) sensitive() bool { return v == indexedNever }
|
||||||
|
|
||||||
|
// returns errNeedMore if there isn't enough data available.
|
||||||
|
// any other error is fatal.
|
||||||
|
// consumes d.buf iff it returns nil.
|
||||||
|
// precondition: must be called with len(d.buf) > 0
|
||||||
|
func (d *Decoder) parseHeaderFieldRepr() error {
|
||||||
|
b := d.buf[0]
|
||||||
|
switch {
|
||||||
|
case b&128 != 0:
|
||||||
|
// Indexed representation.
|
||||||
|
// High bit set?
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.1
|
||||||
|
return d.parseFieldIndexed()
|
||||||
|
case b&192 == 64:
|
||||||
|
// 6.2.1 Literal Header Field with Incremental Indexing
|
||||||
|
// 0b10xxxxxx: top two bits are 10
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1
|
||||||
|
return d.parseFieldLiteral(6, indexedTrue)
|
||||||
|
case b&240 == 0:
|
||||||
|
// 6.2.2 Literal Header Field without Indexing
|
||||||
|
// 0b0000xxxx: top four bits are 0000
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2
|
||||||
|
return d.parseFieldLiteral(4, indexedFalse)
|
||||||
|
case b&240 == 16:
|
||||||
|
// 6.2.3 Literal Header Field never Indexed
|
||||||
|
// 0b0001xxxx: top four bits are 0001
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3
|
||||||
|
return d.parseFieldLiteral(4, indexedNever)
|
||||||
|
case b&224 == 32:
|
||||||
|
// 6.3 Dynamic Table Size Update
|
||||||
|
// Top three bits are '001'.
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.6.3
|
||||||
|
return d.parseDynamicTableSizeUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
return DecodingError{errors.New("invalid encoding")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// (same invariants and behavior as parseHeaderFieldRepr)
|
||||||
|
func (d *Decoder) parseFieldIndexed() error {
|
||||||
|
buf := d.buf
|
||||||
|
idx, buf, err := readVarInt(7, buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hf, ok := d.at(idx)
|
||||||
|
if !ok {
|
||||||
|
return DecodingError{InvalidIndexError(idx)}
|
||||||
|
}
|
||||||
|
d.buf = buf
|
||||||
|
return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value})
|
||||||
|
}
|
||||||
|
|
||||||
|
// (same invariants and behavior as parseHeaderFieldRepr)
|
||||||
|
func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
||||||
|
buf := d.buf
|
||||||
|
nameIdx, buf, err := readVarInt(n, buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var hf HeaderField
|
||||||
|
wantStr := d.emitEnabled || it.indexed()
|
||||||
|
if nameIdx > 0 {
|
||||||
|
ihf, ok := d.at(nameIdx)
|
||||||
|
if !ok {
|
||||||
|
return DecodingError{InvalidIndexError(nameIdx)}
|
||||||
|
}
|
||||||
|
hf.Name = ihf.Name
|
||||||
|
} else {
|
||||||
|
hf.Name, buf, err = d.readString(buf, wantStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hf.Value, buf, err = d.readString(buf, wantStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
d.buf = buf
|
||||||
|
if it.indexed() {
|
||||||
|
d.dynTab.add(hf)
|
||||||
|
}
|
||||||
|
hf.Sensitive = it.sensitive()
|
||||||
|
return d.callEmit(hf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) callEmit(hf HeaderField) error {
|
||||||
|
if d.maxStrLen != 0 {
|
||||||
|
if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen {
|
||||||
|
return ErrStringLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.emitEnabled {
|
||||||
|
d.emit(hf)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// (same invariants and behavior as parseHeaderFieldRepr)
|
||||||
|
func (d *Decoder) parseDynamicTableSizeUpdate() error {
|
||||||
|
buf := d.buf
|
||||||
|
size, buf, err := readVarInt(5, buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if size > uint64(d.dynTab.allowedMaxSize) {
|
||||||
|
return DecodingError{errors.New("dynamic table size update too large")}
|
||||||
|
}
|
||||||
|
d.dynTab.setMaxSize(uint32(size))
|
||||||
|
d.buf = buf
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var errVarintOverflow = DecodingError{errors.New("varint integer overflow")}
|
||||||
|
|
||||||
|
// readVarInt reads an unsigned variable length integer off the
|
||||||
|
// beginning of p. n is the parameter as described in
|
||||||
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1.
|
||||||
|
//
|
||||||
|
// n must always be between 1 and 8.
|
||||||
|
//
|
||||||
|
// The returned remain buffer is either a smaller suffix of p, or err != nil.
|
||||||
|
// The error is errNeedMore if p doesn't contain a complete integer.
|
||||||
|
func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
|
||||||
|
if n < 1 || n > 8 {
|
||||||
|
panic("bad n")
|
||||||
|
}
|
||||||
|
if len(p) == 0 {
|
||||||
|
return 0, p, errNeedMore
|
||||||
|
}
|
||||||
|
i = uint64(p[0])
|
||||||
|
if n < 8 {
|
||||||
|
i &= (1 << uint64(n)) - 1
|
||||||
|
}
|
||||||
|
if i < (1<<uint64(n))-1 {
|
||||||
|
return i, p[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
origP := p
|
||||||
|
p = p[1:]
|
||||||
|
var m uint64
|
||||||
|
for len(p) > 0 {
|
||||||
|
b := p[0]
|
||||||
|
p = p[1:]
|
||||||
|
i += uint64(b&127) << m
|
||||||
|
if b&128 == 0 {
|
||||||
|
return i, p, nil
|
||||||
|
}
|
||||||
|
m += 7
|
||||||
|
if m >= 63 { // TODO: proper overflow check. making this up.
|
||||||
|
return 0, origP, errVarintOverflow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, origP, errNeedMore
|
||||||
|
}
|
||||||
|
|
||||||
|
// readString decodes an hpack string from p.
|
||||||
|
//
|
||||||
|
// wantStr is whether s will be used. If false, decompression and
|
||||||
|
// []byte->string garbage are skipped if s will be ignored
|
||||||
|
// anyway. This does mean that huffman decoding errors for non-indexed
|
||||||
|
// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
|
||||||
|
// is returning an error anyway, and because they're not indexed, the error
|
||||||
|
// won't affect the decoding state.
|
||||||
|
func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return "", p, errNeedMore
|
||||||
|
}
|
||||||
|
isHuff := p[0]&128 != 0
|
||||||
|
strLen, p, err := readVarInt(7, p)
|
||||||
|
if err != nil {
|
||||||
|
return "", p, err
|
||||||
|
}
|
||||||
|
if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
|
||||||
|
return "", nil, ErrStringLength
|
||||||
|
}
|
||||||
|
if uint64(len(p)) < strLen {
|
||||||
|
return "", p, errNeedMore
|
||||||
|
}
|
||||||
|
if !isHuff {
|
||||||
|
if wantStr {
|
||||||
|
s = string(p[:strLen])
|
||||||
|
}
|
||||||
|
return s, p[strLen:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if wantStr {
|
||||||
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
|
buf.Reset() // don't trust others
|
||||||
|
defer bufPool.Put(buf)
|
||||||
|
if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
|
||||||
|
buf.Reset()
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
s = buf.String()
|
||||||
|
buf.Reset() // be nice to GC
|
||||||
|
}
|
||||||
|
return s, p[strLen:], nil
|
||||||
|
}
|
212
vendor/golang.org/x/net/http2/hpack/huffman.go
generated
vendored
Normal file
212
vendor/golang.org/x/net/http2/hpack/huffman.go
generated
vendored
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
// Copyright 2014 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 hpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bufPool = sync.Pool{
|
||||||
|
New: func() interface{} { return new(bytes.Buffer) },
|
||||||
|
}
|
||||||
|
|
||||||
|
// HuffmanDecode decodes the string in v and writes the expanded
|
||||||
|
// result to w, returning the number of bytes written to w and the
|
||||||
|
// Write call's return value. At most one Write call is made.
|
||||||
|
func HuffmanDecode(w io.Writer, v []byte) (int, error) {
|
||||||
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
|
buf.Reset()
|
||||||
|
defer bufPool.Put(buf)
|
||||||
|
if err := huffmanDecode(buf, 0, v); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return w.Write(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// HuffmanDecodeToString decodes the string in v.
|
||||||
|
func HuffmanDecodeToString(v []byte) (string, error) {
|
||||||
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
|
buf.Reset()
|
||||||
|
defer bufPool.Put(buf)
|
||||||
|
if err := huffmanDecode(buf, 0, v); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidHuffman is returned for errors found decoding
|
||||||
|
// Huffman-encoded strings.
|
||||||
|
var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
|
||||||
|
|
||||||
|
// huffmanDecode decodes v to buf.
|
||||||
|
// If maxLen is greater than 0, attempts to write more to buf than
|
||||||
|
// maxLen bytes will return ErrStringLength.
|
||||||
|
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
|
||||||
|
n := rootHuffmanNode
|
||||||
|
// cur is the bit buffer that has not been fed into n.
|
||||||
|
// cbits is the number of low order bits in cur that are valid.
|
||||||
|
// sbits is the number of bits of the symbol prefix being decoded.
|
||||||
|
cur, cbits, sbits := uint(0), uint8(0), uint8(0)
|
||||||
|
for _, b := range v {
|
||||||
|
cur = cur<<8 | uint(b)
|
||||||
|
cbits += 8
|
||||||
|
sbits += 8
|
||||||
|
for cbits >= 8 {
|
||||||
|
idx := byte(cur >> (cbits - 8))
|
||||||
|
n = n.children[idx]
|
||||||
|
if n == nil {
|
||||||
|
return ErrInvalidHuffman
|
||||||
|
}
|
||||||
|
if n.children == nil {
|
||||||
|
if maxLen != 0 && buf.Len() == maxLen {
|
||||||
|
return ErrStringLength
|
||||||
|
}
|
||||||
|
buf.WriteByte(n.sym)
|
||||||
|
cbits -= n.codeLen
|
||||||
|
n = rootHuffmanNode
|
||||||
|
sbits = cbits
|
||||||
|
} else {
|
||||||
|
cbits -= 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for cbits > 0 {
|
||||||
|
n = n.children[byte(cur<<(8-cbits))]
|
||||||
|
if n == nil {
|
||||||
|
return ErrInvalidHuffman
|
||||||
|
}
|
||||||
|
if n.children != nil || n.codeLen > cbits {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if maxLen != 0 && buf.Len() == maxLen {
|
||||||
|
return ErrStringLength
|
||||||
|
}
|
||||||
|
buf.WriteByte(n.sym)
|
||||||
|
cbits -= n.codeLen
|
||||||
|
n = rootHuffmanNode
|
||||||
|
sbits = cbits
|
||||||
|
}
|
||||||
|
if sbits > 7 {
|
||||||
|
// Either there was an incomplete symbol, or overlong padding.
|
||||||
|
// Both are decoding errors per RFC 7541 section 5.2.
|
||||||
|
return ErrInvalidHuffman
|
||||||
|
}
|
||||||
|
if mask := uint(1<<cbits - 1); cur&mask != mask {
|
||||||
|
// Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
|
||||||
|
return ErrInvalidHuffman
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type node struct {
|
||||||
|
// children is non-nil for internal nodes
|
||||||
|
children []*node
|
||||||
|
|
||||||
|
// The following are only valid if children is nil:
|
||||||
|
codeLen uint8 // number of bits that led to the output of sym
|
||||||
|
sym byte // output symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInternalNode() *node {
|
||||||
|
return &node{children: make([]*node, 256)}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootHuffmanNode = newInternalNode()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if len(huffmanCodes) != 256 {
|
||||||
|
panic("unexpected size")
|
||||||
|
}
|
||||||
|
for i, code := range huffmanCodes {
|
||||||
|
addDecoderNode(byte(i), code, huffmanCodeLen[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addDecoderNode(sym byte, code uint32, codeLen uint8) {
|
||||||
|
cur := rootHuffmanNode
|
||||||
|
for codeLen > 8 {
|
||||||
|
codeLen -= 8
|
||||||
|
i := uint8(code >> codeLen)
|
||||||
|
if cur.children[i] == nil {
|
||||||
|
cur.children[i] = newInternalNode()
|
||||||
|
}
|
||||||
|
cur = cur.children[i]
|
||||||
|
}
|
||||||
|
shift := 8 - codeLen
|
||||||
|
start, end := int(uint8(code<<shift)), int(1<<shift)
|
||||||
|
for i := start; i < start+end; i++ {
|
||||||
|
cur.children[i] = &node{sym: sym, codeLen: codeLen}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendHuffmanString appends s, as encoded in Huffman codes, to dst
|
||||||
|
// and returns the extended buffer.
|
||||||
|
func AppendHuffmanString(dst []byte, s string) []byte {
|
||||||
|
rembits := uint8(8)
|
||||||
|
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if rembits == 8 {
|
||||||
|
dst = append(dst, 0)
|
||||||
|
}
|
||||||
|
dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
if rembits < 8 {
|
||||||
|
// special EOS symbol
|
||||||
|
code := uint32(0x3fffffff)
|
||||||
|
nbits := uint8(30)
|
||||||
|
|
||||||
|
t := uint8(code >> (nbits - rembits))
|
||||||
|
dst[len(dst)-1] |= t
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// HuffmanEncodeLength returns the number of bytes required to encode
|
||||||
|
// s in Huffman codes. The result is round up to byte boundary.
|
||||||
|
func HuffmanEncodeLength(s string) uint64 {
|
||||||
|
n := uint64(0)
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
n += uint64(huffmanCodeLen[s[i]])
|
||||||
|
}
|
||||||
|
return (n + 7) / 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// appendByteToHuffmanCode appends Huffman code for c to dst and
|
||||||
|
// returns the extended buffer and the remaining bits in the last
|
||||||
|
// element. The appending is not byte aligned and the remaining bits
|
||||||
|
// in the last element of dst is given in rembits.
|
||||||
|
func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) {
|
||||||
|
code := huffmanCodes[c]
|
||||||
|
nbits := huffmanCodeLen[c]
|
||||||
|
|
||||||
|
for {
|
||||||
|
if rembits > nbits {
|
||||||
|
t := uint8(code << (rembits - nbits))
|
||||||
|
dst[len(dst)-1] |= t
|
||||||
|
rembits -= nbits
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
t := uint8(code >> (nbits - rembits))
|
||||||
|
dst[len(dst)-1] |= t
|
||||||
|
|
||||||
|
nbits -= rembits
|
||||||
|
rembits = 8
|
||||||
|
|
||||||
|
if nbits == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = append(dst, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst, rembits
|
||||||
|
}
|
479
vendor/golang.org/x/net/http2/hpack/tables.go
generated
vendored
Normal file
479
vendor/golang.org/x/net/http2/hpack/tables.go
generated
vendored
Normal file
|
@ -0,0 +1,479 @@
|
||||||
|
// Copyright 2014 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 hpack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// headerFieldTable implements a list of HeaderFields.
|
||||||
|
// This is used to implement the static and dynamic tables.
|
||||||
|
type headerFieldTable struct {
|
||||||
|
// For static tables, entries are never evicted.
|
||||||
|
//
|
||||||
|
// For dynamic tables, entries are evicted from ents[0] and added to the end.
|
||||||
|
// Each entry has a unique id that starts at one and increments for each
|
||||||
|
// entry that is added. This unique id is stable across evictions, meaning
|
||||||
|
// it can be used as a pointer to a specific entry. As in hpack, unique ids
|
||||||
|
// are 1-based. The unique id for ents[k] is k + evictCount + 1.
|
||||||
|
//
|
||||||
|
// Zero is not a valid unique id.
|
||||||
|
//
|
||||||
|
// evictCount should not overflow in any remotely practical situation. In
|
||||||
|
// practice, we will have one dynamic table per HTTP/2 connection. If we
|
||||||
|
// assume a very powerful server that handles 1M QPS per connection and each
|
||||||
|
// request adds (then evicts) 100 entries from the table, it would still take
|
||||||
|
// 2M years for evictCount to overflow.
|
||||||
|
ents []HeaderField
|
||||||
|
evictCount uint64
|
||||||
|
|
||||||
|
// byName maps a HeaderField name to the unique id of the newest entry with
|
||||||
|
// the same name. See above for a definition of "unique id".
|
||||||
|
byName map[string]uint64
|
||||||
|
|
||||||
|
// byNameValue maps a HeaderField name/value pair to the unique id of the newest
|
||||||
|
// entry with the same name and value. See above for a definition of "unique id".
|
||||||
|
byNameValue map[pairNameValue]uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type pairNameValue struct {
|
||||||
|
name, value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *headerFieldTable) init() {
|
||||||
|
t.byName = make(map[string]uint64)
|
||||||
|
t.byNameValue = make(map[pairNameValue]uint64)
|
||||||
|
}
|
||||||
|
|
||||||
|
// len reports the number of entries in the table.
|
||||||
|
func (t *headerFieldTable) len() int {
|
||||||
|
return len(t.ents)
|
||||||
|
}
|
||||||
|
|
||||||
|
// addEntry adds a new entry.
|
||||||
|
func (t *headerFieldTable) addEntry(f HeaderField) {
|
||||||
|
id := uint64(t.len()) + t.evictCount + 1
|
||||||
|
t.byName[f.Name] = id
|
||||||
|
t.byNameValue[pairNameValue{f.Name, f.Value}] = id
|
||||||
|
t.ents = append(t.ents, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// evictOldest evicts the n oldest entries in the table.
|
||||||
|
func (t *headerFieldTable) evictOldest(n int) {
|
||||||
|
if n > t.len() {
|
||||||
|
panic(fmt.Sprintf("evictOldest(%v) on table with %v entries", n, t.len()))
|
||||||
|
}
|
||||||
|
for k := 0; k < n; k++ {
|
||||||
|
f := t.ents[k]
|
||||||
|
id := t.evictCount + uint64(k) + 1
|
||||||
|
if t.byName[f.Name] == id {
|
||||||
|
delete(t.byName, f.Name)
|
||||||
|
}
|
||||||
|
if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id {
|
||||||
|
delete(t.byNameValue, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copy(t.ents, t.ents[n:])
|
||||||
|
for k := t.len() - n; k < t.len(); k++ {
|
||||||
|
t.ents[k] = HeaderField{} // so strings can be garbage collected
|
||||||
|
}
|
||||||
|
t.ents = t.ents[:t.len()-n]
|
||||||
|
if t.evictCount+uint64(n) < t.evictCount {
|
||||||
|
panic("evictCount overflow")
|
||||||
|
}
|
||||||
|
t.evictCount += uint64(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// search finds f in the table. If there is no match, i is 0.
|
||||||
|
// If both name and value match, i is the matched index and nameValueMatch
|
||||||
|
// becomes true. If only name matches, i points to that index and
|
||||||
|
// nameValueMatch becomes false.
|
||||||
|
//
|
||||||
|
// The returned index is a 1-based HPACK index. For dynamic tables, HPACK says
|
||||||
|
// that index 1 should be the newest entry, but t.ents[0] is the oldest entry,
|
||||||
|
// meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic
|
||||||
|
// table, the return value i actually refers to the entry t.ents[t.len()-i].
|
||||||
|
//
|
||||||
|
// All tables are assumed to be a dynamic tables except for the global
|
||||||
|
// staticTable pointer.
|
||||||
|
//
|
||||||
|
// See Section 2.3.3.
|
||||||
|
func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
|
||||||
|
if !f.Sensitive {
|
||||||
|
if id := t.byNameValue[pairNameValue{f.Name, f.Value}]; id != 0 {
|
||||||
|
return t.idToIndex(id), true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if id := t.byName[f.Name]; id != 0 {
|
||||||
|
return t.idToIndex(id), false
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// idToIndex converts a unique id to an HPACK index.
|
||||||
|
// See Section 2.3.3.
|
||||||
|
func (t *headerFieldTable) idToIndex(id uint64) uint64 {
|
||||||
|
if id <= t.evictCount {
|
||||||
|
panic(fmt.Sprintf("id (%v) <= evictCount (%v)", id, t.evictCount))
|
||||||
|
}
|
||||||
|
k := id - t.evictCount - 1 // convert id to an index t.ents[k]
|
||||||
|
if t != staticTable {
|
||||||
|
return uint64(t.len()) - k // dynamic table
|
||||||
|
}
|
||||||
|
return k + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
|
||||||
|
var staticTable = newStaticTable()
|
||||||
|
var staticTableEntries = [...]HeaderField{
|
||||||
|
{Name: ":authority"},
|
||||||
|
{Name: ":method", Value: "GET"},
|
||||||
|
{Name: ":method", Value: "POST"},
|
||||||
|
{Name: ":path", Value: "/"},
|
||||||
|
{Name: ":path", Value: "/index.html"},
|
||||||
|
{Name: ":scheme", Value: "http"},
|
||||||
|
{Name: ":scheme", Value: "https"},
|
||||||
|
{Name: ":status", Value: "200"},
|
||||||
|
{Name: ":status", Value: "204"},
|
||||||
|
{Name: ":status", Value: "206"},
|
||||||
|
{Name: ":status", Value: "304"},
|
||||||
|
{Name: ":status", Value: "400"},
|
||||||
|
{Name: ":status", Value: "404"},
|
||||||
|
{Name: ":status", Value: "500"},
|
||||||
|
{Name: "accept-charset"},
|
||||||
|
{Name: "accept-encoding", Value: "gzip, deflate"},
|
||||||
|
{Name: "accept-language"},
|
||||||
|
{Name: "accept-ranges"},
|
||||||
|
{Name: "accept"},
|
||||||
|
{Name: "access-control-allow-origin"},
|
||||||
|
{Name: "age"},
|
||||||
|
{Name: "allow"},
|
||||||
|
{Name: "authorization"},
|
||||||
|
{Name: "cache-control"},
|
||||||
|
{Name: "content-disposition"},
|
||||||
|
{Name: "content-encoding"},
|
||||||
|
{Name: "content-language"},
|
||||||
|
{Name: "content-length"},
|
||||||
|
{Name: "content-location"},
|
||||||
|
{Name: "content-range"},
|
||||||
|
{Name: "content-type"},
|
||||||
|
{Name: "cookie"},
|
||||||
|
{Name: "date"},
|
||||||
|
{Name: "etag"},
|
||||||
|
{Name: "expect"},
|
||||||
|
{Name: "expires"},
|
||||||
|
{Name: "from"},
|
||||||
|
{Name: "host"},
|
||||||
|
{Name: "if-match"},
|
||||||
|
{Name: "if-modified-since"},
|
||||||
|
{Name: "if-none-match"},
|
||||||
|
{Name: "if-range"},
|
||||||
|
{Name: "if-unmodified-since"},
|
||||||
|
{Name: "last-modified"},
|
||||||
|
{Name: "link"},
|
||||||
|
{Name: "location"},
|
||||||
|
{Name: "max-forwards"},
|
||||||
|
{Name: "proxy-authenticate"},
|
||||||
|
{Name: "proxy-authorization"},
|
||||||
|
{Name: "range"},
|
||||||
|
{Name: "referer"},
|
||||||
|
{Name: "refresh"},
|
||||||
|
{Name: "retry-after"},
|
||||||
|
{Name: "server"},
|
||||||
|
{Name: "set-cookie"},
|
||||||
|
{Name: "strict-transport-security"},
|
||||||
|
{Name: "transfer-encoding"},
|
||||||
|
{Name: "user-agent"},
|
||||||
|
{Name: "vary"},
|
||||||
|
{Name: "via"},
|
||||||
|
{Name: "www-authenticate"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStaticTable() *headerFieldTable {
|
||||||
|
t := &headerFieldTable{}
|
||||||
|
t.init()
|
||||||
|
for _, e := range staticTableEntries[:] {
|
||||||
|
t.addEntry(e)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
var huffmanCodes = [256]uint32{
|
||||||
|
0x1ff8,
|
||||||
|
0x7fffd8,
|
||||||
|
0xfffffe2,
|
||||||
|
0xfffffe3,
|
||||||
|
0xfffffe4,
|
||||||
|
0xfffffe5,
|
||||||
|
0xfffffe6,
|
||||||
|
0xfffffe7,
|
||||||
|
0xfffffe8,
|
||||||
|
0xffffea,
|
||||||
|
0x3ffffffc,
|
||||||
|
0xfffffe9,
|
||||||
|
0xfffffea,
|
||||||
|
0x3ffffffd,
|
||||||
|
0xfffffeb,
|
||||||
|
0xfffffec,
|
||||||
|
0xfffffed,
|
||||||
|
0xfffffee,
|
||||||
|
0xfffffef,
|
||||||
|
0xffffff0,
|
||||||
|
0xffffff1,
|
||||||
|
0xffffff2,
|
||||||
|
0x3ffffffe,
|
||||||
|
0xffffff3,
|
||||||
|
0xffffff4,
|
||||||
|
0xffffff5,
|
||||||
|
0xffffff6,
|
||||||
|
0xffffff7,
|
||||||
|
0xffffff8,
|
||||||
|
0xffffff9,
|
||||||
|
0xffffffa,
|
||||||
|
0xffffffb,
|
||||||
|
0x14,
|
||||||
|
0x3f8,
|
||||||
|
0x3f9,
|
||||||
|
0xffa,
|
||||||
|
0x1ff9,
|
||||||
|
0x15,
|
||||||
|
0xf8,
|
||||||
|
0x7fa,
|
||||||
|
0x3fa,
|
||||||
|
0x3fb,
|
||||||
|
0xf9,
|
||||||
|
0x7fb,
|
||||||
|
0xfa,
|
||||||
|
0x16,
|
||||||
|
0x17,
|
||||||
|
0x18,
|
||||||
|
0x0,
|
||||||
|
0x1,
|
||||||
|
0x2,
|
||||||
|
0x19,
|
||||||
|
0x1a,
|
||||||
|
0x1b,
|
||||||
|
0x1c,
|
||||||
|
0x1d,
|
||||||
|
0x1e,
|
||||||
|
0x1f,
|
||||||
|
0x5c,
|
||||||
|
0xfb,
|
||||||
|
0x7ffc,
|
||||||
|
0x20,
|
||||||
|
0xffb,
|
||||||
|
0x3fc,
|
||||||
|
0x1ffa,
|
||||||
|
0x21,
|
||||||
|
0x5d,
|
||||||
|
0x5e,
|
||||||
|
0x5f,
|
||||||
|
0x60,
|
||||||
|
0x61,
|
||||||
|
0x62,
|
||||||
|
0x63,
|
||||||
|
0x64,
|
||||||
|
0x65,
|
||||||
|
0x66,
|
||||||
|
0x67,
|
||||||
|
0x68,
|
||||||
|
0x69,
|
||||||
|
0x6a,
|
||||||
|
0x6b,
|
||||||
|
0x6c,
|
||||||
|
0x6d,
|
||||||
|
0x6e,
|
||||||
|
0x6f,
|
||||||
|
0x70,
|
||||||
|
0x71,
|
||||||
|
0x72,
|
||||||
|
0xfc,
|
||||||
|
0x73,
|
||||||
|
0xfd,
|
||||||
|
0x1ffb,
|
||||||
|
0x7fff0,
|
||||||
|
0x1ffc,
|
||||||
|
0x3ffc,
|
||||||
|
0x22,
|
||||||
|
0x7ffd,
|
||||||
|
0x3,
|
||||||
|
0x23,
|
||||||
|
0x4,
|
||||||
|
0x24,
|
||||||
|
0x5,
|
||||||
|
0x25,
|
||||||
|
0x26,
|
||||||
|
0x27,
|
||||||
|
0x6,
|
||||||
|
0x74,
|
||||||
|
0x75,
|
||||||
|
0x28,
|
||||||
|
0x29,
|
||||||
|
0x2a,
|
||||||
|
0x7,
|
||||||
|
0x2b,
|
||||||
|
0x76,
|
||||||
|
0x2c,
|
||||||
|
0x8,
|
||||||
|
0x9,
|
||||||
|
0x2d,
|
||||||
|
0x77,
|
||||||
|
0x78,
|
||||||
|
0x79,
|
||||||
|
0x7a,
|
||||||
|
0x7b,
|
||||||
|
0x7ffe,
|
||||||
|
0x7fc,
|
||||||
|
0x3ffd,
|
||||||
|
0x1ffd,
|
||||||
|
0xffffffc,
|
||||||
|
0xfffe6,
|
||||||
|
0x3fffd2,
|
||||||
|
0xfffe7,
|
||||||
|
0xfffe8,
|
||||||
|
0x3fffd3,
|
||||||
|
0x3fffd4,
|
||||||
|
0x3fffd5,
|
||||||
|
0x7fffd9,
|
||||||
|
0x3fffd6,
|
||||||
|
0x7fffda,
|
||||||
|
0x7fffdb,
|
||||||
|
0x7fffdc,
|
||||||
|
0x7fffdd,
|
||||||
|
0x7fffde,
|
||||||
|
0xffffeb,
|
||||||
|
0x7fffdf,
|
||||||
|
0xffffec,
|
||||||
|
0xffffed,
|
||||||
|
0x3fffd7,
|
||||||
|
0x7fffe0,
|
||||||
|
0xffffee,
|
||||||
|
0x7fffe1,
|
||||||
|
0x7fffe2,
|
||||||
|
0x7fffe3,
|
||||||
|
0x7fffe4,
|
||||||
|
0x1fffdc,
|
||||||
|
0x3fffd8,
|
||||||
|
0x7fffe5,
|
||||||
|
0x3fffd9,
|
||||||
|
0x7fffe6,
|
||||||
|
0x7fffe7,
|
||||||
|
0xffffef,
|
||||||
|
0x3fffda,
|
||||||
|
0x1fffdd,
|
||||||
|
0xfffe9,
|
||||||
|
0x3fffdb,
|
||||||
|
0x3fffdc,
|
||||||
|
0x7fffe8,
|
||||||
|
0x7fffe9,
|
||||||
|
0x1fffde,
|
||||||
|
0x7fffea,
|
||||||
|
0x3fffdd,
|
||||||
|
0x3fffde,
|
||||||
|
0xfffff0,
|
||||||
|
0x1fffdf,
|
||||||
|
0x3fffdf,
|
||||||
|
0x7fffeb,
|
||||||
|
0x7fffec,
|
||||||
|
0x1fffe0,
|
||||||
|
0x1fffe1,
|
||||||
|
0x3fffe0,
|
||||||
|
0x1fffe2,
|
||||||
|
0x7fffed,
|
||||||
|
0x3fffe1,
|
||||||
|
0x7fffee,
|
||||||
|
0x7fffef,
|
||||||
|
0xfffea,
|
||||||
|
0x3fffe2,
|
||||||
|
0x3fffe3,
|
||||||
|
0x3fffe4,
|
||||||
|
0x7ffff0,
|
||||||
|
0x3fffe5,
|
||||||
|
0x3fffe6,
|
||||||
|
0x7ffff1,
|
||||||
|
0x3ffffe0,
|
||||||
|
0x3ffffe1,
|
||||||
|
0xfffeb,
|
||||||
|
0x7fff1,
|
||||||
|
0x3fffe7,
|
||||||
|
0x7ffff2,
|
||||||
|
0x3fffe8,
|
||||||
|
0x1ffffec,
|
||||||
|
0x3ffffe2,
|
||||||
|
0x3ffffe3,
|
||||||
|
0x3ffffe4,
|
||||||
|
0x7ffffde,
|
||||||
|
0x7ffffdf,
|
||||||
|
0x3ffffe5,
|
||||||
|
0xfffff1,
|
||||||
|
0x1ffffed,
|
||||||
|
0x7fff2,
|
||||||
|
0x1fffe3,
|
||||||
|
0x3ffffe6,
|
||||||
|
0x7ffffe0,
|
||||||
|
0x7ffffe1,
|
||||||
|
0x3ffffe7,
|
||||||
|
0x7ffffe2,
|
||||||
|
0xfffff2,
|
||||||
|
0x1fffe4,
|
||||||
|
0x1fffe5,
|
||||||
|
0x3ffffe8,
|
||||||
|
0x3ffffe9,
|
||||||
|
0xffffffd,
|
||||||
|
0x7ffffe3,
|
||||||
|
0x7ffffe4,
|
||||||
|
0x7ffffe5,
|
||||||
|
0xfffec,
|
||||||
|
0xfffff3,
|
||||||
|
0xfffed,
|
||||||
|
0x1fffe6,
|
||||||
|
0x3fffe9,
|
||||||
|
0x1fffe7,
|
||||||
|
0x1fffe8,
|
||||||
|
0x7ffff3,
|
||||||
|
0x3fffea,
|
||||||
|
0x3fffeb,
|
||||||
|
0x1ffffee,
|
||||||
|
0x1ffffef,
|
||||||
|
0xfffff4,
|
||||||
|
0xfffff5,
|
||||||
|
0x3ffffea,
|
||||||
|
0x7ffff4,
|
||||||
|
0x3ffffeb,
|
||||||
|
0x7ffffe6,
|
||||||
|
0x3ffffec,
|
||||||
|
0x3ffffed,
|
||||||
|
0x7ffffe7,
|
||||||
|
0x7ffffe8,
|
||||||
|
0x7ffffe9,
|
||||||
|
0x7ffffea,
|
||||||
|
0x7ffffeb,
|
||||||
|
0xffffffe,
|
||||||
|
0x7ffffec,
|
||||||
|
0x7ffffed,
|
||||||
|
0x7ffffee,
|
||||||
|
0x7ffffef,
|
||||||
|
0x7fffff0,
|
||||||
|
0x3ffffee,
|
||||||
|
}
|
||||||
|
|
||||||
|
var huffmanCodeLen = [256]uint8{
|
||||||
|
13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
|
||||||
|
28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||||
|
6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
|
||||||
|
5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10,
|
||||||
|
13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||||
|
7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6,
|
||||||
|
15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5,
|
||||||
|
6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28,
|
||||||
|
20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23,
|
||||||
|
24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24,
|
||||||
|
22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23,
|
||||||
|
21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23,
|
||||||
|
26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25,
|
||||||
|
19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27,
|
||||||
|
20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23,
|
||||||
|
26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26,
|
||||||
|
}
|
391
vendor/golang.org/x/net/http2/http2.go
generated
vendored
Normal file
391
vendor/golang.org/x/net/http2/http2.go
generated
vendored
Normal file
|
@ -0,0 +1,391 @@
|
||||||
|
// Copyright 2014 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 http2 implements the HTTP/2 protocol.
|
||||||
|
//
|
||||||
|
// This package is low-level and intended to be used directly by very
|
||||||
|
// few people. Most users will use it indirectly through the automatic
|
||||||
|
// use by the net/http package (from Go 1.6 and later).
|
||||||
|
// For use in earlier Go versions see ConfigureServer. (Transport support
|
||||||
|
// requires Go 1.6 or later)
|
||||||
|
//
|
||||||
|
// See https://http2.github.io/ for more information on HTTP/2.
|
||||||
|
//
|
||||||
|
// See https://http2.golang.org/ for a test server running this code.
|
||||||
|
//
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/net/lex/httplex"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
VerboseLogs bool
|
||||||
|
logFrameWrites bool
|
||||||
|
logFrameReads bool
|
||||||
|
inTests bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
e := os.Getenv("GODEBUG")
|
||||||
|
if strings.Contains(e, "http2debug=1") {
|
||||||
|
VerboseLogs = true
|
||||||
|
}
|
||||||
|
if strings.Contains(e, "http2debug=2") {
|
||||||
|
VerboseLogs = true
|
||||||
|
logFrameWrites = true
|
||||||
|
logFrameReads = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ClientPreface is the string that must be sent by new
|
||||||
|
// connections from clients.
|
||||||
|
ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
|
||||||
|
|
||||||
|
// SETTINGS_MAX_FRAME_SIZE default
|
||||||
|
// http://http2.github.io/http2-spec/#rfc.section.6.5.2
|
||||||
|
initialMaxFrameSize = 16384
|
||||||
|
|
||||||
|
// NextProtoTLS is the NPN/ALPN protocol negotiated during
|
||||||
|
// HTTP/2's TLS setup.
|
||||||
|
NextProtoTLS = "h2"
|
||||||
|
|
||||||
|
// http://http2.github.io/http2-spec/#SettingValues
|
||||||
|
initialHeaderTableSize = 4096
|
||||||
|
|
||||||
|
initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
|
||||||
|
|
||||||
|
defaultMaxReadFrameSize = 1 << 20
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
clientPreface = []byte(ClientPreface)
|
||||||
|
)
|
||||||
|
|
||||||
|
type streamState int
|
||||||
|
|
||||||
|
// HTTP/2 stream states.
|
||||||
|
//
|
||||||
|
// See http://tools.ietf.org/html/rfc7540#section-5.1.
|
||||||
|
//
|
||||||
|
// For simplicity, the server code merges "reserved (local)" into
|
||||||
|
// "half-closed (remote)". This is one less state transition to track.
|
||||||
|
// The only downside is that we send PUSH_PROMISEs slightly less
|
||||||
|
// liberally than allowable. More discussion here:
|
||||||
|
// https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
|
||||||
|
//
|
||||||
|
// "reserved (remote)" is omitted since the client code does not
|
||||||
|
// support server push.
|
||||||
|
const (
|
||||||
|
stateIdle streamState = iota
|
||||||
|
stateOpen
|
||||||
|
stateHalfClosedLocal
|
||||||
|
stateHalfClosedRemote
|
||||||
|
stateClosed
|
||||||
|
)
|
||||||
|
|
||||||
|
var stateName = [...]string{
|
||||||
|
stateIdle: "Idle",
|
||||||
|
stateOpen: "Open",
|
||||||
|
stateHalfClosedLocal: "HalfClosedLocal",
|
||||||
|
stateHalfClosedRemote: "HalfClosedRemote",
|
||||||
|
stateClosed: "Closed",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st streamState) String() string {
|
||||||
|
return stateName[st]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting is a setting parameter: which setting it is, and its value.
|
||||||
|
type Setting struct {
|
||||||
|
// ID is which setting is being set.
|
||||||
|
// See http://http2.github.io/http2-spec/#SettingValues
|
||||||
|
ID SettingID
|
||||||
|
|
||||||
|
// Val is the value.
|
||||||
|
Val uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Setting) String() string {
|
||||||
|
return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid reports whether the setting is valid.
|
||||||
|
func (s Setting) Valid() error {
|
||||||
|
// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
|
||||||
|
switch s.ID {
|
||||||
|
case SettingEnablePush:
|
||||||
|
if s.Val != 1 && s.Val != 0 {
|
||||||
|
return ConnectionError(ErrCodeProtocol)
|
||||||
|
}
|
||||||
|
case SettingInitialWindowSize:
|
||||||
|
if s.Val > 1<<31-1 {
|
||||||
|
return ConnectionError(ErrCodeFlowControl)
|
||||||
|
}
|
||||||
|
case SettingMaxFrameSize:
|
||||||
|
if s.Val < 16384 || s.Val > 1<<24-1 {
|
||||||
|
return ConnectionError(ErrCodeProtocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A SettingID is an HTTP/2 setting as defined in
|
||||||
|
// http://http2.github.io/http2-spec/#iana-settings
|
||||||
|
type SettingID uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
SettingHeaderTableSize SettingID = 0x1
|
||||||
|
SettingEnablePush SettingID = 0x2
|
||||||
|
SettingMaxConcurrentStreams SettingID = 0x3
|
||||||
|
SettingInitialWindowSize SettingID = 0x4
|
||||||
|
SettingMaxFrameSize SettingID = 0x5
|
||||||
|
SettingMaxHeaderListSize SettingID = 0x6
|
||||||
|
)
|
||||||
|
|
||||||
|
var settingName = map[SettingID]string{
|
||||||
|
SettingHeaderTableSize: "HEADER_TABLE_SIZE",
|
||||||
|
SettingEnablePush: "ENABLE_PUSH",
|
||||||
|
SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
|
||||||
|
SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
|
||||||
|
SettingMaxFrameSize: "MAX_FRAME_SIZE",
|
||||||
|
SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SettingID) String() string {
|
||||||
|
if v, ok := settingName[s]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errInvalidHeaderFieldName = errors.New("http2: invalid header field name")
|
||||||
|
errInvalidHeaderFieldValue = errors.New("http2: invalid header field value")
|
||||||
|
)
|
||||||
|
|
||||||
|
// validWireHeaderFieldName reports whether v is a valid header field
|
||||||
|
// name (key). See httplex.ValidHeaderName for the base rules.
|
||||||
|
//
|
||||||
|
// Further, http2 says:
|
||||||
|
// "Just as in HTTP/1.x, header field names are strings of ASCII
|
||||||
|
// characters that are compared in a case-insensitive
|
||||||
|
// fashion. However, header field names MUST be converted to
|
||||||
|
// lowercase prior to their encoding in HTTP/2. "
|
||||||
|
func validWireHeaderFieldName(v string) bool {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, r := range v {
|
||||||
|
if !httplex.IsTokenRune(r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if 'A' <= r && r <= 'Z' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 100; i <= 999; i++ {
|
||||||
|
if v := http.StatusText(i); v != "" {
|
||||||
|
httpCodeStringCommon[i] = strconv.Itoa(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpCodeString(code int) string {
|
||||||
|
if s, ok := httpCodeStringCommon[code]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return strconv.Itoa(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// from pkg io
|
||||||
|
type stringWriter interface {
|
||||||
|
WriteString(s string) (n int, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A gate lets two goroutines coordinate their activities.
|
||||||
|
type gate chan struct{}
|
||||||
|
|
||||||
|
func (g gate) Done() { g <- struct{}{} }
|
||||||
|
func (g gate) Wait() { <-g }
|
||||||
|
|
||||||
|
// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
|
||||||
|
type closeWaiter chan struct{}
|
||||||
|
|
||||||
|
// Init makes a closeWaiter usable.
|
||||||
|
// It exists because so a closeWaiter value can be placed inside a
|
||||||
|
// larger struct and have the Mutex and Cond's memory in the same
|
||||||
|
// allocation.
|
||||||
|
func (cw *closeWaiter) Init() {
|
||||||
|
*cw = make(chan struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close marks the closeWaiter as closed and unblocks any waiters.
|
||||||
|
func (cw closeWaiter) Close() {
|
||||||
|
close(cw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait waits for the closeWaiter to become closed.
|
||||||
|
func (cw closeWaiter) Wait() {
|
||||||
|
<-cw
|
||||||
|
}
|
||||||
|
|
||||||
|
// bufferedWriter is a buffered writer that writes to w.
|
||||||
|
// Its buffered writer is lazily allocated as needed, to minimize
|
||||||
|
// idle memory usage with many connections.
|
||||||
|
type bufferedWriter struct {
|
||||||
|
w io.Writer // immutable
|
||||||
|
bw *bufio.Writer // non-nil when data is buffered
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBufferedWriter(w io.Writer) *bufferedWriter {
|
||||||
|
return &bufferedWriter{w: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
// bufWriterPoolBufferSize is the size of bufio.Writer's
|
||||||
|
// buffers created using bufWriterPool.
|
||||||
|
//
|
||||||
|
// TODO: pick a less arbitrary value? this is a bit under
|
||||||
|
// (3 x typical 1500 byte MTU) at least. Other than that,
|
||||||
|
// not much thought went into it.
|
||||||
|
const bufWriterPoolBufferSize = 4 << 10
|
||||||
|
|
||||||
|
var bufWriterPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return bufio.NewWriterSize(nil, bufWriterPoolBufferSize)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bufferedWriter) Available() int {
|
||||||
|
if w.bw == nil {
|
||||||
|
return bufWriterPoolBufferSize
|
||||||
|
}
|
||||||
|
return w.bw.Available()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bufferedWriter) Write(p []byte) (n int, err error) {
|
||||||
|
if w.bw == nil {
|
||||||
|
bw := bufWriterPool.Get().(*bufio.Writer)
|
||||||
|
bw.Reset(w.w)
|
||||||
|
w.bw = bw
|
||||||
|
}
|
||||||
|
return w.bw.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bufferedWriter) Flush() error {
|
||||||
|
bw := w.bw
|
||||||
|
if bw == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := bw.Flush()
|
||||||
|
bw.Reset(nil)
|
||||||
|
bufWriterPool.Put(bw)
|
||||||
|
w.bw = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustUint31(v int32) uint32 {
|
||||||
|
if v < 0 || v > 2147483647 {
|
||||||
|
panic("out of range")
|
||||||
|
}
|
||||||
|
return uint32(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bodyAllowedForStatus reports whether a given response status code
|
||||||
|
// permits a body. See RFC 2616, section 4.4.
|
||||||
|
func bodyAllowedForStatus(status int) bool {
|
||||||
|
switch {
|
||||||
|
case status >= 100 && status <= 199:
|
||||||
|
return false
|
||||||
|
case status == 204:
|
||||||
|
return false
|
||||||
|
case status == 304:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpError struct {
|
||||||
|
msg string
|
||||||
|
timeout bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *httpError) Error() string { return e.msg }
|
||||||
|
func (e *httpError) Timeout() bool { return e.timeout }
|
||||||
|
func (e *httpError) Temporary() bool { return true }
|
||||||
|
|
||||||
|
var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
|
||||||
|
|
||||||
|
type connectionStater interface {
|
||||||
|
ConnectionState() tls.ConnectionState
|
||||||
|
}
|
||||||
|
|
||||||
|
var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }}
|
||||||
|
|
||||||
|
type sorter struct {
|
||||||
|
v []string // owned by sorter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sorter) Len() int { return len(s.v) }
|
||||||
|
func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }
|
||||||
|
func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
|
||||||
|
|
||||||
|
// Keys returns the sorted keys of h.
|
||||||
|
//
|
||||||
|
// The returned slice is only valid until s used again or returned to
|
||||||
|
// its pool.
|
||||||
|
func (s *sorter) Keys(h http.Header) []string {
|
||||||
|
keys := s.v[:0]
|
||||||
|
for k := range h {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
s.v = keys
|
||||||
|
sort.Sort(s)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sorter) SortStrings(ss []string) {
|
||||||
|
// Our sorter works on s.v, which sorter owns, so
|
||||||
|
// stash it away while we sort the user's buffer.
|
||||||
|
save := s.v
|
||||||
|
s.v = ss
|
||||||
|
sort.Sort(s)
|
||||||
|
s.v = save
|
||||||
|
}
|
||||||
|
|
||||||
|
// validPseudoPath reports whether v is a valid :path pseudo-header
|
||||||
|
// value. It must be either:
|
||||||
|
//
|
||||||
|
// *) a non-empty string starting with '/'
|
||||||
|
// *) the string '*', for OPTIONS requests.
|
||||||
|
//
|
||||||
|
// For now this is only used a quick check for deciding when to clean
|
||||||
|
// up Opaque URLs before sending requests from the Transport.
|
||||||
|
// See golang.org/issue/16847
|
||||||
|
//
|
||||||
|
// We used to enforce that the path also didn't start with "//", but
|
||||||
|
// Google's GFE accepts such paths and Chrome sends them, so ignore
|
||||||
|
// that part of the spec. See golang.org/issue/19103.
|
||||||
|
func validPseudoPath(v string) bool {
|
||||||
|
return (len(v) > 0 && v[0] == '/') || v == "*"
|
||||||
|
}
|
21
vendor/golang.org/x/net/http2/not_go16.go
generated
vendored
Normal file
21
vendor/golang.org/x/net/http2/not_go16.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// +build !go1.6
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func configureTransport(t1 *http.Transport) (*Transport, error) {
|
||||||
|
return nil, errTransportVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
|
||||||
|
return 0
|
||||||
|
|
||||||
|
}
|
87
vendor/golang.org/x/net/http2/not_go17.go
generated
vendored
Normal file
87
vendor/golang.org/x/net/http2/not_go17.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type contextContext interface {
|
||||||
|
Done() <-chan struct{}
|
||||||
|
Err() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeContext struct{}
|
||||||
|
|
||||||
|
func (fakeContext) Done() <-chan struct{} { return nil }
|
||||||
|
func (fakeContext) Err() error { panic("should not be called") }
|
||||||
|
|
||||||
|
func reqContext(r *http.Request) fakeContext {
|
||||||
|
return fakeContext{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setResponseUncompressed(res *http.Response) {
|
||||||
|
// Nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
type clientTrace struct{}
|
||||||
|
|
||||||
|
func requestTrace(*http.Request) *clientTrace { return nil }
|
||||||
|
func traceGotConn(*http.Request, *ClientConn) {}
|
||||||
|
func traceFirstResponseByte(*clientTrace) {}
|
||||||
|
func traceWroteHeaders(*clientTrace) {}
|
||||||
|
func traceWroteRequest(*clientTrace, error) {}
|
||||||
|
func traceGot100Continue(trace *clientTrace) {}
|
||||||
|
func traceWait100Continue(trace *clientTrace) {}
|
||||||
|
|
||||||
|
func nop() {}
|
||||||
|
|
||||||
|
func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx contextContext, cancel func()) {
|
||||||
|
return nil, nop
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextWithCancel(ctx contextContext) (_ contextContext, cancel func()) {
|
||||||
|
return ctx, nop
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestWithContext(req *http.Request, ctx contextContext) *http.Request {
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
// temporary copy of Go 1.6's private tls.Config.clone:
|
||||||
|
func cloneTLSConfig(c *tls.Config) *tls.Config {
|
||||||
|
return &tls.Config{
|
||||||
|
Rand: c.Rand,
|
||||||
|
Time: c.Time,
|
||||||
|
Certificates: c.Certificates,
|
||||||
|
NameToCertificate: c.NameToCertificate,
|
||||||
|
GetCertificate: c.GetCertificate,
|
||||||
|
RootCAs: c.RootCAs,
|
||||||
|
NextProtos: c.NextProtos,
|
||||||
|
ServerName: c.ServerName,
|
||||||
|
ClientAuth: c.ClientAuth,
|
||||||
|
ClientCAs: c.ClientCAs,
|
||||||
|
InsecureSkipVerify: c.InsecureSkipVerify,
|
||||||
|
CipherSuites: c.CipherSuites,
|
||||||
|
PreferServerCipherSuites: c.PreferServerCipherSuites,
|
||||||
|
SessionTicketsDisabled: c.SessionTicketsDisabled,
|
||||||
|
SessionTicketKey: c.SessionTicketKey,
|
||||||
|
ClientSessionCache: c.ClientSessionCache,
|
||||||
|
MinVersion: c.MinVersion,
|
||||||
|
MaxVersion: c.MaxVersion,
|
||||||
|
CurvePreferences: c.CurvePreferences,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cc *ClientConn) Ping(ctx contextContext) error {
|
||||||
|
return cc.ping(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transport) idleConnTimeout() time.Duration { return 0 }
|
29
vendor/golang.org/x/net/http2/not_go18.go
generated
vendored
Normal file
29
vendor/golang.org/x/net/http2/not_go18.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// +build !go1.8
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func configureServer18(h1 *http.Server, h2 *Server) error {
|
||||||
|
// No IdleTimeout to sync prior to Go 1.8.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldLogPanic(panicValue interface{}) bool {
|
||||||
|
return panicValue != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func reqGetBody(req *http.Request) func() (io.ReadCloser, error) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func reqBodyIsNoBody(io.ReadCloser) bool { return false }
|
||||||
|
|
||||||
|
func go18httpNoBody() io.ReadCloser { return nil } // for tests only
|
16
vendor/golang.org/x/net/http2/not_go19.go
generated
vendored
Normal file
16
vendor/golang.org/x/net/http2/not_go19.go
generated
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2016 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.
|
||||||
|
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func configureServer19(s *http.Server, conf *Server) error {
|
||||||
|
// not supported prior to go1.9
|
||||||
|
return nil
|
||||||
|
}
|
163
vendor/golang.org/x/net/http2/pipe.go
generated
vendored
Normal file
163
vendor/golang.org/x/net/http2/pipe.go
generated
vendored
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
// Copyright 2014 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 http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
|
||||||
|
// io.Pipe except there are no PipeReader/PipeWriter halves, and the
|
||||||
|
// underlying buffer is an interface. (io.Pipe is always unbuffered)
|
||||||
|
type pipe struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
c sync.Cond // c.L lazily initialized to &p.mu
|
||||||
|
b pipeBuffer // nil when done reading
|
||||||
|
err error // read error once empty. non-nil means closed.
|
||||||
|
breakErr error // immediate read error (caller doesn't see rest of b)
|
||||||
|
donec chan struct{} // closed on error
|
||||||
|
readFn func() // optional code to run in Read before error
|
||||||
|
}
|
||||||
|
|
||||||
|
type pipeBuffer interface {
|
||||||
|
Len() int
|
||||||
|
io.Writer
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pipe) Len() int {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.b == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return p.b.Len()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read waits until data is available and copies bytes
|
||||||
|
// from the buffer into p.
|
||||||
|
func (p *pipe) Read(d []byte) (n int, err error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.c.L == nil {
|
||||||
|
p.c.L = &p.mu
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if p.breakErr != nil {
|
||||||
|
return 0, p.breakErr
|
||||||
|
}
|
||||||
|
if p.b != nil && p.b.Len() > 0 {
|
||||||
|
return p.b.Read(d)
|
||||||
|
}
|
||||||
|
if p.err != nil {
|
||||||
|
if p.readFn != nil {
|
||||||
|
p.readFn() // e.g. copy trailers
|
||||||
|
p.readFn = nil // not sticky like p.err
|
||||||
|
}
|
||||||
|
p.b = nil
|
||||||
|
return 0, p.err
|
||||||
|
}
|
||||||
|
p.c.Wait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var errClosedPipeWrite = errors.New("write on closed buffer")
|
||||||
|
|
||||||
|
// Write copies bytes from p into the buffer and wakes a reader.
|
||||||
|
// It is an error to write more data than the buffer can hold.
|
||||||
|
func (p *pipe) Write(d []byte) (n int, err error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.c.L == nil {
|
||||||
|
p.c.L = &p.mu
|
||||||
|
}
|
||||||
|
defer p.c.Signal()
|
||||||
|
if p.err != nil {
|
||||||
|
return 0, errClosedPipeWrite
|
||||||
|
}
|
||||||
|
if p.breakErr != nil {
|
||||||
|
return len(d), nil // discard when there is no reader
|
||||||
|
}
|
||||||
|
return p.b.Write(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseWithError causes the next Read (waking up a current blocked
|
||||||
|
// Read if needed) to return the provided err after all data has been
|
||||||
|
// read.
|
||||||
|
//
|
||||||
|
// The error must be non-nil.
|
||||||
|
func (p *pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) }
|
||||||
|
|
||||||
|
// BreakWithError causes the next Read (waking up a current blocked
|
||||||
|
// Read if needed) to return the provided err immediately, without
|
||||||
|
// waiting for unread data.
|
||||||
|
func (p *pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) }
|
||||||
|
|
||||||
|
// closeWithErrorAndCode is like CloseWithError but also sets some code to run
|
||||||
|
// in the caller's goroutine before returning the error.
|
||||||
|
func (p *pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) }
|
||||||
|
|
||||||
|
func (p *pipe) closeWithError(dst *error, err error, fn func()) {
|
||||||
|
if err == nil {
|
||||||
|
panic("err must be non-nil")
|
||||||
|
}
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.c.L == nil {
|
||||||
|
p.c.L = &p.mu
|
||||||
|
}
|
||||||
|
defer p.c.Signal()
|
||||||
|
if *dst != nil {
|
||||||
|
// Already been done.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.readFn = fn
|
||||||
|
if dst == &p.breakErr {
|
||||||
|
p.b = nil
|
||||||
|
}
|
||||||
|
*dst = err
|
||||||
|
p.closeDoneLocked()
|
||||||
|
}
|
||||||
|
|
||||||
|
// requires p.mu be held.
|
||||||
|
func (p *pipe) closeDoneLocked() {
|
||||||
|
if p.donec == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Close if unclosed. This isn't racy since we always
|
||||||
|
// hold p.mu while closing.
|
||||||
|
select {
|
||||||
|
case <-p.donec:
|
||||||
|
default:
|
||||||
|
close(p.donec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns the error (if any) first set by BreakWithError or CloseWithError.
|
||||||
|
func (p *pipe) Err() error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.breakErr != nil {
|
||||||
|
return p.breakErr
|
||||||
|
}
|
||||||
|
return p.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done returns a channel which is closed if and when this pipe is closed
|
||||||
|
// with CloseWithError.
|
||||||
|
func (p *pipe) Done() <-chan struct{} {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.donec == nil {
|
||||||
|
p.donec = make(chan struct{})
|
||||||
|
if p.err != nil || p.breakErr != nil {
|
||||||
|
// Already hit an error.
|
||||||
|
p.closeDoneLocked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p.donec
|
||||||
|
}
|
2857
vendor/golang.org/x/net/http2/server.go
generated
vendored
Normal file
2857
vendor/golang.org/x/net/http2/server.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
2275
vendor/golang.org/x/net/http2/transport.go
generated
vendored
Normal file
2275
vendor/golang.org/x/net/http2/transport.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
370
vendor/golang.org/x/net/http2/write.go
generated
vendored
Normal file
370
vendor/golang.org/x/net/http2/write.go
generated
vendored
Normal file
|
@ -0,0 +1,370 @@
|
||||||
|
// Copyright 2014 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 http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/http2/hpack"
|
||||||
|
"golang.org/x/net/lex/httplex"
|
||||||
|
)
|
||||||
|
|
||||||
|
// writeFramer is implemented by any type that is used to write frames.
|
||||||
|
type writeFramer interface {
|
||||||
|
writeFrame(writeContext) error
|
||||||
|
|
||||||
|
// staysWithinBuffer reports whether this writer promises that
|
||||||
|
// it will only write less than or equal to size bytes, and it
|
||||||
|
// won't Flush the write context.
|
||||||
|
staysWithinBuffer(size int) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeContext is the interface needed by the various frame writer
|
||||||
|
// types below. All the writeFrame methods below are scheduled via the
|
||||||
|
// frame writing scheduler (see writeScheduler in writesched.go).
|
||||||
|
//
|
||||||
|
// This interface is implemented by *serverConn.
|
||||||
|
//
|
||||||
|
// TODO: decide whether to a) use this in the client code (which didn't
|
||||||
|
// end up using this yet, because it has a simpler design, not
|
||||||
|
// currently implementing priorities), or b) delete this and
|
||||||
|
// make the server code a bit more concrete.
|
||||||
|
type writeContext interface {
|
||||||
|
Framer() *Framer
|
||||||
|
Flush() error
|
||||||
|
CloseConn() error
|
||||||
|
// HeaderEncoder returns an HPACK encoder that writes to the
|
||||||
|
// returned buffer.
|
||||||
|
HeaderEncoder() (*hpack.Encoder, *bytes.Buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeEndsStream reports whether w writes a frame that will transition
|
||||||
|
// the stream to a half-closed local state. This returns false for RST_STREAM,
|
||||||
|
// which closes the entire stream (not just the local half).
|
||||||
|
func writeEndsStream(w writeFramer) bool {
|
||||||
|
switch v := w.(type) {
|
||||||
|
case *writeData:
|
||||||
|
return v.endStream
|
||||||
|
case *writeResHeaders:
|
||||||
|
return v.endStream
|
||||||
|
case nil:
|
||||||
|
// This can only happen if the caller reuses w after it's
|
||||||
|
// been intentionally nil'ed out to prevent use. Keep this
|
||||||
|
// here to catch future refactoring breaking it.
|
||||||
|
panic("writeEndsStream called on nil writeFramer")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type flushFrameWriter struct{}
|
||||||
|
|
||||||
|
func (flushFrameWriter) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flushFrameWriter) staysWithinBuffer(max int) bool { return false }
|
||||||
|
|
||||||
|
type writeSettings []Setting
|
||||||
|
|
||||||
|
func (s writeSettings) staysWithinBuffer(max int) bool {
|
||||||
|
const settingSize = 6 // uint16 + uint32
|
||||||
|
return frameHeaderLen+settingSize*len(s) <= max
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s writeSettings) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Framer().WriteSettings([]Setting(s)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
type writeGoAway struct {
|
||||||
|
maxStreamID uint32
|
||||||
|
code ErrCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *writeGoAway) writeFrame(ctx writeContext) error {
|
||||||
|
err := ctx.Framer().WriteGoAway(p.maxStreamID, p.code, nil)
|
||||||
|
if p.code != 0 {
|
||||||
|
ctx.Flush() // ignore error: we're hanging up on them anyway
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
ctx.CloseConn()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*writeGoAway) staysWithinBuffer(max int) bool { return false } // flushes
|
||||||
|
|
||||||
|
type writeData struct {
|
||||||
|
streamID uint32
|
||||||
|
p []byte
|
||||||
|
endStream bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writeData) String() string {
|
||||||
|
return fmt.Sprintf("writeData(stream=%d, p=%d, endStream=%v)", w.streamID, len(w.p), w.endStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writeData) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writeData) staysWithinBuffer(max int) bool {
|
||||||
|
return frameHeaderLen+len(w.p) <= max
|
||||||
|
}
|
||||||
|
|
||||||
|
// handlerPanicRST is the message sent from handler goroutines when
|
||||||
|
// the handler panics.
|
||||||
|
type handlerPanicRST struct {
|
||||||
|
StreamID uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hp handlerPanicRST) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Framer().WriteRSTStream(hp.StreamID, ErrCodeInternal)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hp handlerPanicRST) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
|
||||||
|
|
||||||
|
func (se StreamError) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (se StreamError) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
|
||||||
|
|
||||||
|
type writePingAck struct{ pf *PingFrame }
|
||||||
|
|
||||||
|
func (w writePingAck) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Framer().WritePing(true, w.pf.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w writePingAck) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.pf.Data) <= max }
|
||||||
|
|
||||||
|
type writeSettingsAck struct{}
|
||||||
|
|
||||||
|
func (writeSettingsAck) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Framer().WriteSettingsAck()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (writeSettingsAck) staysWithinBuffer(max int) bool { return frameHeaderLen <= max }
|
||||||
|
|
||||||
|
// splitHeaderBlock splits headerBlock into fragments so that each fragment fits
|
||||||
|
// in a single frame, then calls fn for each fragment. firstFrag/lastFrag are true
|
||||||
|
// for the first/last fragment, respectively.
|
||||||
|
func splitHeaderBlock(ctx writeContext, headerBlock []byte, fn func(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error) error {
|
||||||
|
// For now we're lazy and just pick the minimum MAX_FRAME_SIZE
|
||||||
|
// that all peers must support (16KB). Later we could care
|
||||||
|
// more and send larger frames if the peer advertised it, but
|
||||||
|
// there's little point. Most headers are small anyway (so we
|
||||||
|
// generally won't have CONTINUATION frames), and extra frames
|
||||||
|
// only waste 9 bytes anyway.
|
||||||
|
const maxFrameSize = 16384
|
||||||
|
|
||||||
|
first := true
|
||||||
|
for len(headerBlock) > 0 {
|
||||||
|
frag := headerBlock
|
||||||
|
if len(frag) > maxFrameSize {
|
||||||
|
frag = frag[:maxFrameSize]
|
||||||
|
}
|
||||||
|
headerBlock = headerBlock[len(frag):]
|
||||||
|
if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
|
||||||
|
// for HTTP response headers or trailers from a server handler.
|
||||||
|
type writeResHeaders struct {
|
||||||
|
streamID uint32
|
||||||
|
httpResCode int // 0 means no ":status" line
|
||||||
|
h http.Header // may be nil
|
||||||
|
trailers []string // if non-nil, which keys of h to write. nil means all.
|
||||||
|
endStream bool
|
||||||
|
|
||||||
|
date string
|
||||||
|
contentType string
|
||||||
|
contentLength string
|
||||||
|
}
|
||||||
|
|
||||||
|
func encKV(enc *hpack.Encoder, k, v string) {
|
||||||
|
if VerboseLogs {
|
||||||
|
log.Printf("http2: server encoding header %q = %q", k, v)
|
||||||
|
}
|
||||||
|
enc.WriteField(hpack.HeaderField{Name: k, Value: v})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writeResHeaders) staysWithinBuffer(max int) bool {
|
||||||
|
// TODO: this is a common one. It'd be nice to return true
|
||||||
|
// here and get into the fast path if we could be clever and
|
||||||
|
// calculate the size fast enough, or at least a conservative
|
||||||
|
// uppper bound that usually fires. (Maybe if w.h and
|
||||||
|
// w.trailers are nil, so we don't need to enumerate it.)
|
||||||
|
// Otherwise I'm afraid that just calculating the length to
|
||||||
|
// answer this question would be slower than the ~2µs benefit.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writeResHeaders) writeFrame(ctx writeContext) error {
|
||||||
|
enc, buf := ctx.HeaderEncoder()
|
||||||
|
buf.Reset()
|
||||||
|
|
||||||
|
if w.httpResCode != 0 {
|
||||||
|
encKV(enc, ":status", httpCodeString(w.httpResCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
encodeHeaders(enc, w.h, w.trailers)
|
||||||
|
|
||||||
|
if w.contentType != "" {
|
||||||
|
encKV(enc, "content-type", w.contentType)
|
||||||
|
}
|
||||||
|
if w.contentLength != "" {
|
||||||
|
encKV(enc, "content-length", w.contentLength)
|
||||||
|
}
|
||||||
|
if w.date != "" {
|
||||||
|
encKV(enc, "date", w.date)
|
||||||
|
}
|
||||||
|
|
||||||
|
headerBlock := buf.Bytes()
|
||||||
|
if len(headerBlock) == 0 && w.trailers == nil {
|
||||||
|
panic("unexpected empty hpack")
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writeResHeaders) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
|
||||||
|
if firstFrag {
|
||||||
|
return ctx.Framer().WriteHeaders(HeadersFrameParam{
|
||||||
|
StreamID: w.streamID,
|
||||||
|
BlockFragment: frag,
|
||||||
|
EndStream: w.endStream,
|
||||||
|
EndHeaders: lastFrag,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// writePushPromise is a request to write a PUSH_PROMISE and 0+ CONTINUATION frames.
|
||||||
|
type writePushPromise struct {
|
||||||
|
streamID uint32 // pusher stream
|
||||||
|
method string // for :method
|
||||||
|
url *url.URL // for :scheme, :authority, :path
|
||||||
|
h http.Header
|
||||||
|
|
||||||
|
// Creates an ID for a pushed stream. This runs on serveG just before
|
||||||
|
// the frame is written. The returned ID is copied to promisedID.
|
||||||
|
allocatePromisedID func() (uint32, error)
|
||||||
|
promisedID uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writePushPromise) staysWithinBuffer(max int) bool {
|
||||||
|
// TODO: see writeResHeaders.staysWithinBuffer
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writePushPromise) writeFrame(ctx writeContext) error {
|
||||||
|
enc, buf := ctx.HeaderEncoder()
|
||||||
|
buf.Reset()
|
||||||
|
|
||||||
|
encKV(enc, ":method", w.method)
|
||||||
|
encKV(enc, ":scheme", w.url.Scheme)
|
||||||
|
encKV(enc, ":authority", w.url.Host)
|
||||||
|
encKV(enc, ":path", w.url.RequestURI())
|
||||||
|
encodeHeaders(enc, w.h, nil)
|
||||||
|
|
||||||
|
headerBlock := buf.Bytes()
|
||||||
|
if len(headerBlock) == 0 {
|
||||||
|
panic("unexpected empty hpack")
|
||||||
|
}
|
||||||
|
|
||||||
|
return splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *writePushPromise) writeHeaderBlock(ctx writeContext, frag []byte, firstFrag, lastFrag bool) error {
|
||||||
|
if firstFrag {
|
||||||
|
return ctx.Framer().WritePushPromise(PushPromiseParam{
|
||||||
|
StreamID: w.streamID,
|
||||||
|
PromiseID: w.promisedID,
|
||||||
|
BlockFragment: frag,
|
||||||
|
EndHeaders: lastFrag,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type write100ContinueHeadersFrame struct {
|
||||||
|
streamID uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w write100ContinueHeadersFrame) writeFrame(ctx writeContext) error {
|
||||||
|
enc, buf := ctx.HeaderEncoder()
|
||||||
|
buf.Reset()
|
||||||
|
encKV(enc, ":status", "100")
|
||||||
|
return ctx.Framer().WriteHeaders(HeadersFrameParam{
|
||||||
|
StreamID: w.streamID,
|
||||||
|
BlockFragment: buf.Bytes(),
|
||||||
|
EndStream: false,
|
||||||
|
EndHeaders: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
|
||||||
|
// Sloppy but conservative:
|
||||||
|
return 9+2*(len(":status")+len("100")) <= max
|
||||||
|
}
|
||||||
|
|
||||||
|
type writeWindowUpdate struct {
|
||||||
|
streamID uint32 // or 0 for conn-level
|
||||||
|
n uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wu writeWindowUpdate) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max }
|
||||||
|
|
||||||
|
func (wu writeWindowUpdate) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeHeaders encodes an http.Header. If keys is not nil, then (k, h[k])
|
||||||
|
// is encoded only only if k is in keys.
|
||||||
|
func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
|
||||||
|
if keys == nil {
|
||||||
|
sorter := sorterPool.Get().(*sorter)
|
||||||
|
// Using defer here, since the returned keys from the
|
||||||
|
// sorter.Keys method is only valid until the sorter
|
||||||
|
// is returned:
|
||||||
|
defer sorterPool.Put(sorter)
|
||||||
|
keys = sorter.Keys(h)
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
vv := h[k]
|
||||||
|
k = lowerHeader(k)
|
||||||
|
if !validWireHeaderFieldName(k) {
|
||||||
|
// Skip it as backup paranoia. Per
|
||||||
|
// golang.org/issue/14048, these should
|
||||||
|
// already be rejected at a higher level.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isTE := k == "transfer-encoding"
|
||||||
|
for _, v := range vv {
|
||||||
|
if !httplex.ValidHeaderFieldValue(v) {
|
||||||
|
// TODO: return an error? golang.org/issue/14048
|
||||||
|
// For now just omit it.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
|
||||||
|
if isTE && v != "trailers" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
encKV(enc, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
242
vendor/golang.org/x/net/http2/writesched.go
generated
vendored
Normal file
242
vendor/golang.org/x/net/http2/writesched.go
generated
vendored
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
// Copyright 2014 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 http2
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// WriteScheduler is the interface implemented by HTTP/2 write schedulers.
|
||||||
|
// Methods are never called concurrently.
|
||||||
|
type WriteScheduler interface {
|
||||||
|
// OpenStream opens a new stream in the write scheduler.
|
||||||
|
// It is illegal to call this with streamID=0 or with a streamID that is
|
||||||
|
// already open -- the call may panic.
|
||||||
|
OpenStream(streamID uint32, options OpenStreamOptions)
|
||||||
|
|
||||||
|
// CloseStream closes a stream in the write scheduler. Any frames queued on
|
||||||
|
// this stream should be discarded. It is illegal to call this on a stream
|
||||||
|
// that is not open -- the call may panic.
|
||||||
|
CloseStream(streamID uint32)
|
||||||
|
|
||||||
|
// AdjustStream adjusts the priority of the given stream. This may be called
|
||||||
|
// on a stream that has not yet been opened or has been closed. Note that
|
||||||
|
// RFC 7540 allows PRIORITY frames to be sent on streams in any state. See:
|
||||||
|
// https://tools.ietf.org/html/rfc7540#section-5.1
|
||||||
|
AdjustStream(streamID uint32, priority PriorityParam)
|
||||||
|
|
||||||
|
// Push queues a frame in the scheduler. In most cases, this will not be
|
||||||
|
// called with wr.StreamID()!=0 unless that stream is currently open. The one
|
||||||
|
// exception is RST_STREAM frames, which may be sent on idle or closed streams.
|
||||||
|
Push(wr FrameWriteRequest)
|
||||||
|
|
||||||
|
// Pop dequeues the next frame to write. Returns false if no frames can
|
||||||
|
// be written. Frames with a given wr.StreamID() are Pop'd in the same
|
||||||
|
// order they are Push'd.
|
||||||
|
Pop() (wr FrameWriteRequest, ok bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
|
||||||
|
type OpenStreamOptions struct {
|
||||||
|
// PusherID is zero if the stream was initiated by the client. Otherwise,
|
||||||
|
// PusherID names the stream that pushed the newly opened stream.
|
||||||
|
PusherID uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// FrameWriteRequest is a request to write a frame.
|
||||||
|
type FrameWriteRequest struct {
|
||||||
|
// write is the interface value that does the writing, once the
|
||||||
|
// WriteScheduler has selected this frame to write. The write
|
||||||
|
// functions are all defined in write.go.
|
||||||
|
write writeFramer
|
||||||
|
|
||||||
|
// stream is the stream on which this frame will be written.
|
||||||
|
// nil for non-stream frames like PING and SETTINGS.
|
||||||
|
stream *stream
|
||||||
|
|
||||||
|
// done, if non-nil, must be a buffered channel with space for
|
||||||
|
// 1 message and is sent the return value from write (or an
|
||||||
|
// earlier error) when the frame has been written.
|
||||||
|
done chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
// StreamID returns the id of the stream this frame will be written to.
|
||||||
|
// 0 is used for non-stream frames such as PING and SETTINGS.
|
||||||
|
func (wr FrameWriteRequest) StreamID() uint32 {
|
||||||
|
if wr.stream == nil {
|
||||||
|
if se, ok := wr.write.(StreamError); ok {
|
||||||
|
// (*serverConn).resetStream doesn't set
|
||||||
|
// stream because it doesn't necessarily have
|
||||||
|
// one. So special case this type of write
|
||||||
|
// message.
|
||||||
|
return se.StreamID
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return wr.stream.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataSize returns the number of flow control bytes that must be consumed
|
||||||
|
// to write this entire frame. This is 0 for non-DATA frames.
|
||||||
|
func (wr FrameWriteRequest) DataSize() int {
|
||||||
|
if wd, ok := wr.write.(*writeData); ok {
|
||||||
|
return len(wd.p)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume consumes min(n, available) bytes from this frame, where available
|
||||||
|
// is the number of flow control bytes available on the stream. Consume returns
|
||||||
|
// 0, 1, or 2 frames, where the integer return value gives the number of frames
|
||||||
|
// returned.
|
||||||
|
//
|
||||||
|
// If flow control prevents consuming any bytes, this returns (_, _, 0). If
|
||||||
|
// the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
|
||||||
|
// returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
|
||||||
|
// 'rest' contains the remaining bytes. The consumed bytes are deducted from the
|
||||||
|
// underlying stream's flow control budget.
|
||||||
|
func (wr FrameWriteRequest) Consume(n int32) (FrameWriteRequest, FrameWriteRequest, int) {
|
||||||
|
var empty FrameWriteRequest
|
||||||
|
|
||||||
|
// Non-DATA frames are always consumed whole.
|
||||||
|
wd, ok := wr.write.(*writeData)
|
||||||
|
if !ok || len(wd.p) == 0 {
|
||||||
|
return wr, empty, 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Might need to split after applying limits.
|
||||||
|
allowed := wr.stream.flow.available()
|
||||||
|
if n < allowed {
|
||||||
|
allowed = n
|
||||||
|
}
|
||||||
|
if wr.stream.sc.maxFrameSize < allowed {
|
||||||
|
allowed = wr.stream.sc.maxFrameSize
|
||||||
|
}
|
||||||
|
if allowed <= 0 {
|
||||||
|
return empty, empty, 0
|
||||||
|
}
|
||||||
|
if len(wd.p) > int(allowed) {
|
||||||
|
wr.stream.flow.take(allowed)
|
||||||
|
consumed := FrameWriteRequest{
|
||||||
|
stream: wr.stream,
|
||||||
|
write: &writeData{
|
||||||
|
streamID: wd.streamID,
|
||||||
|
p: wd.p[:allowed],
|
||||||
|
// Even if the original had endStream set, there
|
||||||
|
// are bytes remaining because len(wd.p) > allowed,
|
||||||
|
// so we know endStream is false.
|
||||||
|
endStream: false,
|
||||||
|
},
|
||||||
|
// Our caller is blocking on the final DATA frame, not
|
||||||
|
// this intermediate frame, so no need to wait.
|
||||||
|
done: nil,
|
||||||
|
}
|
||||||
|
rest := FrameWriteRequest{
|
||||||
|
stream: wr.stream,
|
||||||
|
write: &writeData{
|
||||||
|
streamID: wd.streamID,
|
||||||
|
p: wd.p[allowed:],
|
||||||
|
endStream: wd.endStream,
|
||||||
|
},
|
||||||
|
done: wr.done,
|
||||||
|
}
|
||||||
|
return consumed, rest, 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// The frame is consumed whole.
|
||||||
|
// NB: This cast cannot overflow because allowed is <= math.MaxInt32.
|
||||||
|
wr.stream.flow.take(int32(len(wd.p)))
|
||||||
|
return wr, empty, 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is for debugging only.
|
||||||
|
func (wr FrameWriteRequest) String() string {
|
||||||
|
var des string
|
||||||
|
if s, ok := wr.write.(fmt.Stringer); ok {
|
||||||
|
des = s.String()
|
||||||
|
} else {
|
||||||
|
des = fmt.Sprintf("%T", wr.write)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
|
||||||
|
}
|
||||||
|
|
||||||
|
// replyToWriter sends err to wr.done and panics if the send must block
|
||||||
|
// This does nothing if wr.done is nil.
|
||||||
|
func (wr *FrameWriteRequest) replyToWriter(err error) {
|
||||||
|
if wr.done == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case wr.done <- err:
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
|
||||||
|
}
|
||||||
|
wr.write = nil // prevent use (assume it's tainted after wr.done send)
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeQueue is used by implementations of WriteScheduler.
|
||||||
|
type writeQueue struct {
|
||||||
|
s []FrameWriteRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *writeQueue) empty() bool { return len(q.s) == 0 }
|
||||||
|
|
||||||
|
func (q *writeQueue) push(wr FrameWriteRequest) {
|
||||||
|
q.s = append(q.s, wr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *writeQueue) shift() FrameWriteRequest {
|
||||||
|
if len(q.s) == 0 {
|
||||||
|
panic("invalid use of queue")
|
||||||
|
}
|
||||||
|
wr := q.s[0]
|
||||||
|
// TODO: less copy-happy queue.
|
||||||
|
copy(q.s, q.s[1:])
|
||||||
|
q.s[len(q.s)-1] = FrameWriteRequest{}
|
||||||
|
q.s = q.s[:len(q.s)-1]
|
||||||
|
return wr
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume consumes up to n bytes from q.s[0]. If the frame is
|
||||||
|
// entirely consumed, it is removed from the queue. If the frame
|
||||||
|
// is partially consumed, the frame is kept with the consumed
|
||||||
|
// bytes removed. Returns true iff any bytes were consumed.
|
||||||
|
func (q *writeQueue) consume(n int32) (FrameWriteRequest, bool) {
|
||||||
|
if len(q.s) == 0 {
|
||||||
|
return FrameWriteRequest{}, false
|
||||||
|
}
|
||||||
|
consumed, rest, numresult := q.s[0].Consume(n)
|
||||||
|
switch numresult {
|
||||||
|
case 0:
|
||||||
|
return FrameWriteRequest{}, false
|
||||||
|
case 1:
|
||||||
|
q.shift()
|
||||||
|
case 2:
|
||||||
|
q.s[0] = rest
|
||||||
|
}
|
||||||
|
return consumed, true
|
||||||
|
}
|
||||||
|
|
||||||
|
type writeQueuePool []*writeQueue
|
||||||
|
|
||||||
|
// put inserts an unused writeQueue into the pool.
|
||||||
|
func (p *writeQueuePool) put(q *writeQueue) {
|
||||||
|
for i := range q.s {
|
||||||
|
q.s[i] = FrameWriteRequest{}
|
||||||
|
}
|
||||||
|
q.s = q.s[:0]
|
||||||
|
*p = append(*p, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// get returns an empty writeQueue.
|
||||||
|
func (p *writeQueuePool) get() *writeQueue {
|
||||||
|
ln := len(*p)
|
||||||
|
if ln == 0 {
|
||||||
|
return new(writeQueue)
|
||||||
|
}
|
||||||
|
x := ln - 1
|
||||||
|
q := (*p)[x]
|
||||||
|
(*p)[x] = nil
|
||||||
|
*p = (*p)[:x]
|
||||||
|
return q
|
||||||
|
}
|
452
vendor/golang.org/x/net/http2/writesched_priority.go
generated
vendored
Normal file
452
vendor/golang.org/x/net/http2/writesched_priority.go
generated
vendored
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
// Copyright 2016 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 http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 7540, Section 5.3.5: the default weight is 16.
|
||||||
|
const priorityDefaultWeight = 15 // 16 = 15 + 1
|
||||||
|
|
||||||
|
// PriorityWriteSchedulerConfig configures a priorityWriteScheduler.
|
||||||
|
type PriorityWriteSchedulerConfig struct {
|
||||||
|
// MaxClosedNodesInTree controls the maximum number of closed streams to
|
||||||
|
// retain in the priority tree. Setting this to zero saves a small amount
|
||||||
|
// of memory at the cost of performance.
|
||||||
|
//
|
||||||
|
// See RFC 7540, Section 5.3.4:
|
||||||
|
// "It is possible for a stream to become closed while prioritization
|
||||||
|
// information ... is in transit. ... This potentially creates suboptimal
|
||||||
|
// prioritization, since the stream could be given a priority that is
|
||||||
|
// different from what is intended. To avoid these problems, an endpoint
|
||||||
|
// SHOULD retain stream prioritization state for a period after streams
|
||||||
|
// become closed. The longer state is retained, the lower the chance that
|
||||||
|
// streams are assigned incorrect or default priority values."
|
||||||
|
MaxClosedNodesInTree int
|
||||||
|
|
||||||
|
// MaxIdleNodesInTree controls the maximum number of idle streams to
|
||||||
|
// retain in the priority tree. Setting this to zero saves a small amount
|
||||||
|
// of memory at the cost of performance.
|
||||||
|
//
|
||||||
|
// See RFC 7540, Section 5.3.4:
|
||||||
|
// Similarly, streams that are in the "idle" state can be assigned
|
||||||
|
// priority or become a parent of other streams. This allows for the
|
||||||
|
// creation of a grouping node in the dependency tree, which enables
|
||||||
|
// more flexible expressions of priority. Idle streams begin with a
|
||||||
|
// default priority (Section 5.3.5).
|
||||||
|
MaxIdleNodesInTree int
|
||||||
|
|
||||||
|
// ThrottleOutOfOrderWrites enables write throttling to help ensure that
|
||||||
|
// data is delivered in priority order. This works around a race where
|
||||||
|
// stream B depends on stream A and both streams are about to call Write
|
||||||
|
// to queue DATA frames. If B wins the race, a naive scheduler would eagerly
|
||||||
|
// write as much data from B as possible, but this is suboptimal because A
|
||||||
|
// is a higher-priority stream. With throttling enabled, we write a small
|
||||||
|
// amount of data from B to minimize the amount of bandwidth that B can
|
||||||
|
// steal from A.
|
||||||
|
ThrottleOutOfOrderWrites bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPriorityWriteScheduler constructs a WriteScheduler that schedules
|
||||||
|
// frames by following HTTP/2 priorities as described in RFC 7540 Section 5.3.
|
||||||
|
// If cfg is nil, default options are used.
|
||||||
|
func NewPriorityWriteScheduler(cfg *PriorityWriteSchedulerConfig) WriteScheduler {
|
||||||
|
if cfg == nil {
|
||||||
|
// For justification of these defaults, see:
|
||||||
|
// https://docs.google.com/document/d/1oLhNg1skaWD4_DtaoCxdSRN5erEXrH-KnLrMwEpOtFY
|
||||||
|
cfg = &PriorityWriteSchedulerConfig{
|
||||||
|
MaxClosedNodesInTree: 10,
|
||||||
|
MaxIdleNodesInTree: 10,
|
||||||
|
ThrottleOutOfOrderWrites: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ws := &priorityWriteScheduler{
|
||||||
|
nodes: make(map[uint32]*priorityNode),
|
||||||
|
maxClosedNodesInTree: cfg.MaxClosedNodesInTree,
|
||||||
|
maxIdleNodesInTree: cfg.MaxIdleNodesInTree,
|
||||||
|
enableWriteThrottle: cfg.ThrottleOutOfOrderWrites,
|
||||||
|
}
|
||||||
|
ws.nodes[0] = &ws.root
|
||||||
|
if cfg.ThrottleOutOfOrderWrites {
|
||||||
|
ws.writeThrottleLimit = 1024
|
||||||
|
} else {
|
||||||
|
ws.writeThrottleLimit = math.MaxInt32
|
||||||
|
}
|
||||||
|
return ws
|
||||||
|
}
|
||||||
|
|
||||||
|
type priorityNodeState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
priorityNodeOpen priorityNodeState = iota
|
||||||
|
priorityNodeClosed
|
||||||
|
priorityNodeIdle
|
||||||
|
)
|
||||||
|
|
||||||
|
// priorityNode is a node in an HTTP/2 priority tree.
|
||||||
|
// Each node is associated with a single stream ID.
|
||||||
|
// See RFC 7540, Section 5.3.
|
||||||
|
type priorityNode struct {
|
||||||
|
q writeQueue // queue of pending frames to write
|
||||||
|
id uint32 // id of the stream, or 0 for the root of the tree
|
||||||
|
weight uint8 // the actual weight is weight+1, so the value is in [1,256]
|
||||||
|
state priorityNodeState // open | closed | idle
|
||||||
|
bytes int64 // number of bytes written by this node, or 0 if closed
|
||||||
|
subtreeBytes int64 // sum(node.bytes) of all nodes in this subtree
|
||||||
|
|
||||||
|
// These links form the priority tree.
|
||||||
|
parent *priorityNode
|
||||||
|
kids *priorityNode // start of the kids list
|
||||||
|
prev, next *priorityNode // doubly-linked list of siblings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *priorityNode) setParent(parent *priorityNode) {
|
||||||
|
if n == parent {
|
||||||
|
panic("setParent to self")
|
||||||
|
}
|
||||||
|
if n.parent == parent {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Unlink from current parent.
|
||||||
|
if parent := n.parent; parent != nil {
|
||||||
|
if n.prev == nil {
|
||||||
|
parent.kids = n.next
|
||||||
|
} else {
|
||||||
|
n.prev.next = n.next
|
||||||
|
}
|
||||||
|
if n.next != nil {
|
||||||
|
n.next.prev = n.prev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Link to new parent.
|
||||||
|
// If parent=nil, remove n from the tree.
|
||||||
|
// Always insert at the head of parent.kids (this is assumed by walkReadyInOrder).
|
||||||
|
n.parent = parent
|
||||||
|
if parent == nil {
|
||||||
|
n.next = nil
|
||||||
|
n.prev = nil
|
||||||
|
} else {
|
||||||
|
n.next = parent.kids
|
||||||
|
n.prev = nil
|
||||||
|
if n.next != nil {
|
||||||
|
n.next.prev = n
|
||||||
|
}
|
||||||
|
parent.kids = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *priorityNode) addBytes(b int64) {
|
||||||
|
n.bytes += b
|
||||||
|
for ; n != nil; n = n.parent {
|
||||||
|
n.subtreeBytes += b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// walkReadyInOrder iterates over the tree in priority order, calling f for each node
|
||||||
|
// with a non-empty write queue. When f returns true, this funcion returns true and the
|
||||||
|
// walk halts. tmp is used as scratch space for sorting.
|
||||||
|
//
|
||||||
|
// f(n, openParent) takes two arguments: the node to visit, n, and a bool that is true
|
||||||
|
// if any ancestor p of n is still open (ignoring the root node).
|
||||||
|
func (n *priorityNode) walkReadyInOrder(openParent bool, tmp *[]*priorityNode, f func(*priorityNode, bool) bool) bool {
|
||||||
|
if !n.q.empty() && f(n, openParent) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if n.kids == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't consider the root "open" when updating openParent since
|
||||||
|
// we can't send data frames on the root stream (only control frames).
|
||||||
|
if n.id != 0 {
|
||||||
|
openParent = openParent || (n.state == priorityNodeOpen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common case: only one kid or all kids have the same weight.
|
||||||
|
// Some clients don't use weights; other clients (like web browsers)
|
||||||
|
// use mostly-linear priority trees.
|
||||||
|
w := n.kids.weight
|
||||||
|
needSort := false
|
||||||
|
for k := n.kids.next; k != nil; k = k.next {
|
||||||
|
if k.weight != w {
|
||||||
|
needSort = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !needSort {
|
||||||
|
for k := n.kids; k != nil; k = k.next {
|
||||||
|
if k.walkReadyInOrder(openParent, tmp, f) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uncommon case: sort the child nodes. We remove the kids from the parent,
|
||||||
|
// then re-insert after sorting so we can reuse tmp for future sort calls.
|
||||||
|
*tmp = (*tmp)[:0]
|
||||||
|
for n.kids != nil {
|
||||||
|
*tmp = append(*tmp, n.kids)
|
||||||
|
n.kids.setParent(nil)
|
||||||
|
}
|
||||||
|
sort.Sort(sortPriorityNodeSiblings(*tmp))
|
||||||
|
for i := len(*tmp) - 1; i >= 0; i-- {
|
||||||
|
(*tmp)[i].setParent(n) // setParent inserts at the head of n.kids
|
||||||
|
}
|
||||||
|
for k := n.kids; k != nil; k = k.next {
|
||||||
|
if k.walkReadyInOrder(openParent, tmp, f) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type sortPriorityNodeSiblings []*priorityNode
|
||||||
|
|
||||||
|
func (z sortPriorityNodeSiblings) Len() int { return len(z) }
|
||||||
|
func (z sortPriorityNodeSiblings) Swap(i, k int) { z[i], z[k] = z[k], z[i] }
|
||||||
|
func (z sortPriorityNodeSiblings) Less(i, k int) bool {
|
||||||
|
// Prefer the subtree that has sent fewer bytes relative to its weight.
|
||||||
|
// See sections 5.3.2 and 5.3.4.
|
||||||
|
wi, bi := float64(z[i].weight+1), float64(z[i].subtreeBytes)
|
||||||
|
wk, bk := float64(z[k].weight+1), float64(z[k].subtreeBytes)
|
||||||
|
if bi == 0 && bk == 0 {
|
||||||
|
return wi >= wk
|
||||||
|
}
|
||||||
|
if bk == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return bi/bk <= wi/wk
|
||||||
|
}
|
||||||
|
|
||||||
|
type priorityWriteScheduler struct {
|
||||||
|
// root is the root of the priority tree, where root.id = 0.
|
||||||
|
// The root queues control frames that are not associated with any stream.
|
||||||
|
root priorityNode
|
||||||
|
|
||||||
|
// nodes maps stream ids to priority tree nodes.
|
||||||
|
nodes map[uint32]*priorityNode
|
||||||
|
|
||||||
|
// maxID is the maximum stream id in nodes.
|
||||||
|
maxID uint32
|
||||||
|
|
||||||
|
// lists of nodes that have been closed or are idle, but are kept in
|
||||||
|
// the tree for improved prioritization. When the lengths exceed either
|
||||||
|
// maxClosedNodesInTree or maxIdleNodesInTree, old nodes are discarded.
|
||||||
|
closedNodes, idleNodes []*priorityNode
|
||||||
|
|
||||||
|
// From the config.
|
||||||
|
maxClosedNodesInTree int
|
||||||
|
maxIdleNodesInTree int
|
||||||
|
writeThrottleLimit int32
|
||||||
|
enableWriteThrottle bool
|
||||||
|
|
||||||
|
// tmp is scratch space for priorityNode.walkReadyInOrder to reduce allocations.
|
||||||
|
tmp []*priorityNode
|
||||||
|
|
||||||
|
// pool of empty queues for reuse.
|
||||||
|
queuePool writeQueuePool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *priorityWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
|
||||||
|
// The stream may be currently idle but cannot be opened or closed.
|
||||||
|
if curr := ws.nodes[streamID]; curr != nil {
|
||||||
|
if curr.state != priorityNodeIdle {
|
||||||
|
panic(fmt.Sprintf("stream %d already opened", streamID))
|
||||||
|
}
|
||||||
|
curr.state = priorityNodeOpen
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFC 7540, Section 5.3.5:
|
||||||
|
// "All streams are initially assigned a non-exclusive dependency on stream 0x0.
|
||||||
|
// Pushed streams initially depend on their associated stream. In both cases,
|
||||||
|
// streams are assigned a default weight of 16."
|
||||||
|
parent := ws.nodes[options.PusherID]
|
||||||
|
if parent == nil {
|
||||||
|
parent = &ws.root
|
||||||
|
}
|
||||||
|
n := &priorityNode{
|
||||||
|
q: *ws.queuePool.get(),
|
||||||
|
id: streamID,
|
||||||
|
weight: priorityDefaultWeight,
|
||||||
|
state: priorityNodeOpen,
|
||||||
|
}
|
||||||
|
n.setParent(parent)
|
||||||
|
ws.nodes[streamID] = n
|
||||||
|
if streamID > ws.maxID {
|
||||||
|
ws.maxID = streamID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *priorityWriteScheduler) CloseStream(streamID uint32) {
|
||||||
|
if streamID == 0 {
|
||||||
|
panic("violation of WriteScheduler interface: cannot close stream 0")
|
||||||
|
}
|
||||||
|
if ws.nodes[streamID] == nil {
|
||||||
|
panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", streamID))
|
||||||
|
}
|
||||||
|
if ws.nodes[streamID].state != priorityNodeOpen {
|
||||||
|
panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", streamID))
|
||||||
|
}
|
||||||
|
|
||||||
|
n := ws.nodes[streamID]
|
||||||
|
n.state = priorityNodeClosed
|
||||||
|
n.addBytes(-n.bytes)
|
||||||
|
|
||||||
|
q := n.q
|
||||||
|
ws.queuePool.put(&q)
|
||||||
|
n.q.s = nil
|
||||||
|
if ws.maxClosedNodesInTree > 0 {
|
||||||
|
ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n)
|
||||||
|
} else {
|
||||||
|
ws.removeNode(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *priorityWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {
|
||||||
|
if streamID == 0 {
|
||||||
|
panic("adjustPriority on root")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If streamID does not exist, there are two cases:
|
||||||
|
// - A closed stream that has been removed (this will have ID <= maxID)
|
||||||
|
// - An idle stream that is being used for "grouping" (this will have ID > maxID)
|
||||||
|
n := ws.nodes[streamID]
|
||||||
|
if n == nil {
|
||||||
|
if streamID <= ws.maxID || ws.maxIdleNodesInTree == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ws.maxID = streamID
|
||||||
|
n = &priorityNode{
|
||||||
|
q: *ws.queuePool.get(),
|
||||||
|
id: streamID,
|
||||||
|
weight: priorityDefaultWeight,
|
||||||
|
state: priorityNodeIdle,
|
||||||
|
}
|
||||||
|
n.setParent(&ws.root)
|
||||||
|
ws.nodes[streamID] = n
|
||||||
|
ws.addClosedOrIdleNode(&ws.idleNodes, ws.maxIdleNodesInTree, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section 5.3.1: A dependency on a stream that is not currently in the tree
|
||||||
|
// results in that stream being given a default priority (Section 5.3.5).
|
||||||
|
parent := ws.nodes[priority.StreamDep]
|
||||||
|
if parent == nil {
|
||||||
|
n.setParent(&ws.root)
|
||||||
|
n.weight = priorityDefaultWeight
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if the client tries to make a node its own parent.
|
||||||
|
if n == parent {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section 5.3.3:
|
||||||
|
// "If a stream is made dependent on one of its own dependencies, the
|
||||||
|
// formerly dependent stream is first moved to be dependent on the
|
||||||
|
// reprioritized stream's previous parent. The moved dependency retains
|
||||||
|
// its weight."
|
||||||
|
//
|
||||||
|
// That is: if parent depends on n, move parent to depend on n.parent.
|
||||||
|
for x := parent.parent; x != nil; x = x.parent {
|
||||||
|
if x == n {
|
||||||
|
parent.setParent(n.parent)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Section 5.3.3: The exclusive flag causes the stream to become the sole
|
||||||
|
// dependency of its parent stream, causing other dependencies to become
|
||||||
|
// dependent on the exclusive stream.
|
||||||
|
if priority.Exclusive {
|
||||||
|
k := parent.kids
|
||||||
|
for k != nil {
|
||||||
|
next := k.next
|
||||||
|
if k != n {
|
||||||
|
k.setParent(n)
|
||||||
|
}
|
||||||
|
k = next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n.setParent(parent)
|
||||||
|
n.weight = priority.Weight
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *priorityWriteScheduler) Push(wr FrameWriteRequest) {
|
||||||
|
var n *priorityNode
|
||||||
|
if id := wr.StreamID(); id == 0 {
|
||||||
|
n = &ws.root
|
||||||
|
} else {
|
||||||
|
n = ws.nodes[id]
|
||||||
|
if n == nil {
|
||||||
|
// id is an idle or closed stream. wr should not be a HEADERS or
|
||||||
|
// DATA frame. However, wr can be a RST_STREAM. In this case, we
|
||||||
|
// push wr onto the root, rather than creating a new priorityNode,
|
||||||
|
// since RST_STREAM is tiny and the stream's priority is unknown
|
||||||
|
// anyway. See issue #17919.
|
||||||
|
if wr.DataSize() > 0 {
|
||||||
|
panic("add DATA on non-open stream")
|
||||||
|
}
|
||||||
|
n = &ws.root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n.q.push(wr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *priorityWriteScheduler) Pop() (wr FrameWriteRequest, ok bool) {
|
||||||
|
ws.root.walkReadyInOrder(false, &ws.tmp, func(n *priorityNode, openParent bool) bool {
|
||||||
|
limit := int32(math.MaxInt32)
|
||||||
|
if openParent {
|
||||||
|
limit = ws.writeThrottleLimit
|
||||||
|
}
|
||||||
|
wr, ok = n.q.consume(limit)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n.addBytes(int64(wr.DataSize()))
|
||||||
|
// If B depends on A and B continuously has data available but A
|
||||||
|
// does not, gradually increase the throttling limit to allow B to
|
||||||
|
// steal more and more bandwidth from A.
|
||||||
|
if openParent {
|
||||||
|
ws.writeThrottleLimit += 1024
|
||||||
|
if ws.writeThrottleLimit < 0 {
|
||||||
|
ws.writeThrottleLimit = math.MaxInt32
|
||||||
|
}
|
||||||
|
} else if ws.enableWriteThrottle {
|
||||||
|
ws.writeThrottleLimit = 1024
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return wr, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *priorityWriteScheduler) addClosedOrIdleNode(list *[]*priorityNode, maxSize int, n *priorityNode) {
|
||||||
|
if maxSize == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(*list) == maxSize {
|
||||||
|
// Remove the oldest node, then shift left.
|
||||||
|
ws.removeNode((*list)[0])
|
||||||
|
x := (*list)[1:]
|
||||||
|
copy(*list, x)
|
||||||
|
*list = (*list)[:len(x)]
|
||||||
|
}
|
||||||
|
*list = append(*list, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *priorityWriteScheduler) removeNode(n *priorityNode) {
|
||||||
|
for k := n.kids; k != nil; k = k.next {
|
||||||
|
k.setParent(n.parent)
|
||||||
|
}
|
||||||
|
n.setParent(nil)
|
||||||
|
delete(ws.nodes, n.id)
|
||||||
|
}
|
72
vendor/golang.org/x/net/http2/writesched_random.go
generated
vendored
Normal file
72
vendor/golang.org/x/net/http2/writesched_random.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2014 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 http2
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
// NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2
|
||||||
|
// priorities. Control frames like SETTINGS and PING are written before DATA
|
||||||
|
// frames, but if no control frames are queued and multiple streams have queued
|
||||||
|
// HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
|
||||||
|
func NewRandomWriteScheduler() WriteScheduler {
|
||||||
|
return &randomWriteScheduler{sq: make(map[uint32]*writeQueue)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type randomWriteScheduler struct {
|
||||||
|
// zero are frames not associated with a specific stream.
|
||||||
|
zero writeQueue
|
||||||
|
|
||||||
|
// sq contains the stream-specific queues, keyed by stream ID.
|
||||||
|
// When a stream is idle or closed, it's deleted from the map.
|
||||||
|
sq map[uint32]*writeQueue
|
||||||
|
|
||||||
|
// pool of empty queues for reuse.
|
||||||
|
queuePool writeQueuePool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *randomWriteScheduler) OpenStream(streamID uint32, options OpenStreamOptions) {
|
||||||
|
// no-op: idle streams are not tracked
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *randomWriteScheduler) CloseStream(streamID uint32) {
|
||||||
|
q, ok := ws.sq[streamID]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(ws.sq, streamID)
|
||||||
|
ws.queuePool.put(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *randomWriteScheduler) AdjustStream(streamID uint32, priority PriorityParam) {
|
||||||
|
// no-op: priorities are ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) {
|
||||||
|
id := wr.StreamID()
|
||||||
|
if id == 0 {
|
||||||
|
ws.zero.push(wr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
q, ok := ws.sq[id]
|
||||||
|
if !ok {
|
||||||
|
q = ws.queuePool.get()
|
||||||
|
ws.sq[id] = q
|
||||||
|
}
|
||||||
|
q.push(wr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *randomWriteScheduler) Pop() (FrameWriteRequest, bool) {
|
||||||
|
// Control frames first.
|
||||||
|
if !ws.zero.empty() {
|
||||||
|
return ws.zero.shift(), true
|
||||||
|
}
|
||||||
|
// Iterate over all non-idle streams until finding one that can be consumed.
|
||||||
|
for _, q := range ws.sq {
|
||||||
|
if wr, ok := q.consume(math.MaxInt32); ok {
|
||||||
|
return wr, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FrameWriteRequest{}, false
|
||||||
|
}
|
680
vendor/golang.org/x/net/idna/idna.go
generated
vendored
Normal file
680
vendor/golang.org/x/net/idna/idna.go
generated
vendored
Normal file
|
@ -0,0 +1,680 @@
|
||||||
|
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||||
|
|
||||||
|
// Copyright 2016 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 idna implements IDNA2008 using the compatibility processing
|
||||||
|
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to
|
||||||
|
// deal with the transition from IDNA2003.
|
||||||
|
//
|
||||||
|
// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC
|
||||||
|
// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894.
|
||||||
|
// UTS #46 is defined in http://www.unicode.org/reports/tr46.
|
||||||
|
// See http://unicode.org/cldr/utility/idna.jsp for a visualization of the
|
||||||
|
// differences between these two standards.
|
||||||
|
package idna
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"golang.org/x/text/secure/bidirule"
|
||||||
|
"golang.org/x/text/unicode/norm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NOTE: Unlike common practice in Go APIs, the functions will return a
|
||||||
|
// sanitized domain name in case of errors. Browsers sometimes use a partially
|
||||||
|
// evaluated string as lookup.
|
||||||
|
// TODO: the current error handling is, in my opinion, the least opinionated.
|
||||||
|
// Other strategies are also viable, though:
|
||||||
|
// Option 1) Return an empty string in case of error, but allow the user to
|
||||||
|
// specify explicitly which errors to ignore.
|
||||||
|
// Option 2) Return the partially evaluated string if it is itself a valid
|
||||||
|
// string, otherwise return the empty string in case of error.
|
||||||
|
// Option 3) Option 1 and 2.
|
||||||
|
// Option 4) Always return an empty string for now and implement Option 1 as
|
||||||
|
// needed, and document that the return string may not be empty in case of
|
||||||
|
// error in the future.
|
||||||
|
// I think Option 1 is best, but it is quite opinionated.
|
||||||
|
|
||||||
|
// ToASCII is a wrapper for Punycode.ToASCII.
|
||||||
|
func ToASCII(s string) (string, error) {
|
||||||
|
return Punycode.process(s, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToUnicode is a wrapper for Punycode.ToUnicode.
|
||||||
|
func ToUnicode(s string) (string, error) {
|
||||||
|
return Punycode.process(s, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Option configures a Profile at creation time.
|
||||||
|
type Option func(*options)
|
||||||
|
|
||||||
|
// Transitional sets a Profile to use the Transitional mapping as defined in UTS
|
||||||
|
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the
|
||||||
|
// transitional mapping provides a compromise between IDNA2003 and IDNA2008
|
||||||
|
// compatibility. It is used by most browsers when resolving domain names. This
|
||||||
|
// option is only meaningful if combined with MapForLookup.
|
||||||
|
func Transitional(transitional bool) Option {
|
||||||
|
return func(o *options) { o.transitional = true }
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
|
||||||
|
// are longer than allowed by the RFC.
|
||||||
|
func VerifyDNSLength(verify bool) Option {
|
||||||
|
return func(o *options) { o.verifyDNSLength = verify }
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveLeadingDots removes leading label separators. Leading runes that map to
|
||||||
|
// dots, such as U+3002, are removed as well.
|
||||||
|
//
|
||||||
|
// This is the behavior suggested by the UTS #46 and is adopted by some
|
||||||
|
// browsers.
|
||||||
|
func RemoveLeadingDots(remove bool) Option {
|
||||||
|
return func(o *options) { o.removeLeadingDots = remove }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateLabels sets whether to check the mandatory label validation criteria
|
||||||
|
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
|
||||||
|
// of hyphens ('-'), normalization, validity of runes, and the context rules.
|
||||||
|
func ValidateLabels(enable bool) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
// Don't override existing mappings, but set one that at least checks
|
||||||
|
// normalization if it is not set.
|
||||||
|
if o.mapping == nil && enable {
|
||||||
|
o.mapping = normalize
|
||||||
|
}
|
||||||
|
o.trie = trie
|
||||||
|
o.validateLabels = enable
|
||||||
|
o.fromPuny = validateFromPunycode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StrictDomainName limits the set of permissable ASCII characters to those
|
||||||
|
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
|
||||||
|
// hyphen). This is set by default for MapForLookup and ValidateForRegistration.
|
||||||
|
//
|
||||||
|
// This option is useful, for instance, for browsers that allow characters
|
||||||
|
// outside this range, for example a '_' (U+005F LOW LINE). See
|
||||||
|
// http://www.rfc-editor.org/std/std3.txt for more details This option
|
||||||
|
// corresponds to the UseSTD3ASCIIRules option in UTS #46.
|
||||||
|
func StrictDomainName(use bool) Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.trie = trie
|
||||||
|
o.useSTD3Rules = use
|
||||||
|
o.fromPuny = validateFromPunycode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: the following options pull in tables. The tables should not be linked
|
||||||
|
// in as long as the options are not used.
|
||||||
|
|
||||||
|
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application
|
||||||
|
// that relies on proper validation of labels should include this rule.
|
||||||
|
func BidiRule() Option {
|
||||||
|
return func(o *options) { o.bidirule = bidirule.ValidString }
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateForRegistration sets validation options to verify that a given IDN is
|
||||||
|
// properly formatted for registration as defined by Section 4 of RFC 5891.
|
||||||
|
func ValidateForRegistration() Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.mapping = validateRegistration
|
||||||
|
StrictDomainName(true)(o)
|
||||||
|
ValidateLabels(true)(o)
|
||||||
|
VerifyDNSLength(true)(o)
|
||||||
|
BidiRule()(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapForLookup sets validation and mapping options such that a given IDN is
|
||||||
|
// transformed for domain name lookup according to the requirements set out in
|
||||||
|
// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894,
|
||||||
|
// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option
|
||||||
|
// to add this check.
|
||||||
|
//
|
||||||
|
// The mappings include normalization and mapping case, width and other
|
||||||
|
// compatibility mappings.
|
||||||
|
func MapForLookup() Option {
|
||||||
|
return func(o *options) {
|
||||||
|
o.mapping = validateAndMap
|
||||||
|
StrictDomainName(true)(o)
|
||||||
|
ValidateLabels(true)(o)
|
||||||
|
RemoveLeadingDots(true)(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type options struct {
|
||||||
|
transitional bool
|
||||||
|
useSTD3Rules bool
|
||||||
|
validateLabels bool
|
||||||
|
verifyDNSLength bool
|
||||||
|
removeLeadingDots bool
|
||||||
|
|
||||||
|
trie *idnaTrie
|
||||||
|
|
||||||
|
// fromPuny calls validation rules when converting A-labels to U-labels.
|
||||||
|
fromPuny func(p *Profile, s string) error
|
||||||
|
|
||||||
|
// mapping implements a validation and mapping step as defined in RFC 5895
|
||||||
|
// or UTS 46, tailored to, for example, domain registration or lookup.
|
||||||
|
mapping func(p *Profile, s string) (string, error)
|
||||||
|
|
||||||
|
// bidirule, if specified, checks whether s conforms to the Bidi Rule
|
||||||
|
// defined in RFC 5893.
|
||||||
|
bidirule func(s string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Profile defines the configuration of an IDNA mapper.
|
||||||
|
type Profile struct {
|
||||||
|
options
|
||||||
|
}
|
||||||
|
|
||||||
|
func apply(o *options, opts []Option) {
|
||||||
|
for _, f := range opts {
|
||||||
|
f(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new Profile.
|
||||||
|
//
|
||||||
|
// With no options, the returned Profile is the most permissive and equals the
|
||||||
|
// Punycode Profile. Options can be passed to further restrict the Profile. The
|
||||||
|
// MapForLookup and ValidateForRegistration options set a collection of options,
|
||||||
|
// for lookup and registration purposes respectively, which can be tailored by
|
||||||
|
// adding more fine-grained options, where later options override earlier
|
||||||
|
// options.
|
||||||
|
func New(o ...Option) *Profile {
|
||||||
|
p := &Profile{}
|
||||||
|
apply(&p.options, o)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToASCII converts a domain or domain label to its ASCII form. For example,
|
||||||
|
// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
|
||||||
|
// ToASCII("golang") is "golang". If an error is encountered it will return
|
||||||
|
// an error and a (partially) processed result.
|
||||||
|
func (p *Profile) ToASCII(s string) (string, error) {
|
||||||
|
return p.process(s, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToUnicode converts a domain or domain label to its Unicode form. For example,
|
||||||
|
// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and
|
||||||
|
// ToUnicode("golang") is "golang". If an error is encountered it will return
|
||||||
|
// an error and a (partially) processed result.
|
||||||
|
func (p *Profile) ToUnicode(s string) (string, error) {
|
||||||
|
pp := *p
|
||||||
|
pp.transitional = false
|
||||||
|
return pp.process(s, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String reports a string with a description of the profile for debugging
|
||||||
|
// purposes. The string format may change with different versions.
|
||||||
|
func (p *Profile) String() string {
|
||||||
|
s := ""
|
||||||
|
if p.transitional {
|
||||||
|
s = "Transitional"
|
||||||
|
} else {
|
||||||
|
s = "NonTransitional"
|
||||||
|
}
|
||||||
|
if p.useSTD3Rules {
|
||||||
|
s += ":UseSTD3Rules"
|
||||||
|
}
|
||||||
|
if p.validateLabels {
|
||||||
|
s += ":ValidateLabels"
|
||||||
|
}
|
||||||
|
if p.verifyDNSLength {
|
||||||
|
s += ":VerifyDNSLength"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Punycode is a Profile that does raw punycode processing with a minimum
|
||||||
|
// of validation.
|
||||||
|
Punycode *Profile = punycode
|
||||||
|
|
||||||
|
// Lookup is the recommended profile for looking up domain names, according
|
||||||
|
// to Section 5 of RFC 5891. The exact configuration of this profile may
|
||||||
|
// change over time.
|
||||||
|
Lookup *Profile = lookup
|
||||||
|
|
||||||
|
// Display is the recommended profile for displaying domain names.
|
||||||
|
// The configuration of this profile may change over time.
|
||||||
|
Display *Profile = display
|
||||||
|
|
||||||
|
// Registration is the recommended profile for checking whether a given
|
||||||
|
// IDN is valid for registration, according to Section 4 of RFC 5891.
|
||||||
|
Registration *Profile = registration
|
||||||
|
|
||||||
|
punycode = &Profile{}
|
||||||
|
lookup = &Profile{options{
|
||||||
|
transitional: true,
|
||||||
|
useSTD3Rules: true,
|
||||||
|
validateLabels: true,
|
||||||
|
removeLeadingDots: true,
|
||||||
|
trie: trie,
|
||||||
|
fromPuny: validateFromPunycode,
|
||||||
|
mapping: validateAndMap,
|
||||||
|
bidirule: bidirule.ValidString,
|
||||||
|
}}
|
||||||
|
display = &Profile{options{
|
||||||
|
useSTD3Rules: true,
|
||||||
|
validateLabels: true,
|
||||||
|
removeLeadingDots: true,
|
||||||
|
trie: trie,
|
||||||
|
fromPuny: validateFromPunycode,
|
||||||
|
mapping: validateAndMap,
|
||||||
|
bidirule: bidirule.ValidString,
|
||||||
|
}}
|
||||||
|
registration = &Profile{options{
|
||||||
|
useSTD3Rules: true,
|
||||||
|
validateLabels: true,
|
||||||
|
verifyDNSLength: true,
|
||||||
|
trie: trie,
|
||||||
|
fromPuny: validateFromPunycode,
|
||||||
|
mapping: validateRegistration,
|
||||||
|
bidirule: bidirule.ValidString,
|
||||||
|
}}
|
||||||
|
|
||||||
|
// TODO: profiles
|
||||||
|
// Register: recommended for approving domain names: don't do any mappings
|
||||||
|
// but rather reject on invalid input. Bundle or block deviation characters.
|
||||||
|
)
|
||||||
|
|
||||||
|
type labelError struct{ label, code_ string }
|
||||||
|
|
||||||
|
func (e labelError) code() string { return e.code_ }
|
||||||
|
func (e labelError) Error() string {
|
||||||
|
return fmt.Sprintf("idna: invalid label %q", e.label)
|
||||||
|
}
|
||||||
|
|
||||||
|
type runeError rune
|
||||||
|
|
||||||
|
func (e runeError) code() string { return "P1" }
|
||||||
|
func (e runeError) Error() string {
|
||||||
|
return fmt.Sprintf("idna: disallowed rune %U", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// process implements the algorithm described in section 4 of UTS #46,
|
||||||
|
// see http://www.unicode.org/reports/tr46.
|
||||||
|
func (p *Profile) process(s string, toASCII bool) (string, error) {
|
||||||
|
var err error
|
||||||
|
if p.mapping != nil {
|
||||||
|
s, err = p.mapping(p, s)
|
||||||
|
}
|
||||||
|
// Remove leading empty labels.
|
||||||
|
if p.removeLeadingDots {
|
||||||
|
for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// It seems like we should only create this error on ToASCII, but the
|
||||||
|
// UTS 46 conformance tests suggests we should always check this.
|
||||||
|
if err == nil && p.verifyDNSLength && s == "" {
|
||||||
|
err = &labelError{s, "A4"}
|
||||||
|
}
|
||||||
|
labels := labelIter{orig: s}
|
||||||
|
for ; !labels.done(); labels.next() {
|
||||||
|
label := labels.label()
|
||||||
|
if label == "" {
|
||||||
|
// Empty labels are not okay. The label iterator skips the last
|
||||||
|
// label if it is empty.
|
||||||
|
if err == nil && p.verifyDNSLength {
|
||||||
|
err = &labelError{s, "A4"}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(label, acePrefix) {
|
||||||
|
u, err2 := decode(label[len(acePrefix):])
|
||||||
|
if err2 != nil {
|
||||||
|
if err == nil {
|
||||||
|
err = err2
|
||||||
|
}
|
||||||
|
// Spec says keep the old label.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
labels.set(u)
|
||||||
|
if err == nil && p.validateLabels {
|
||||||
|
err = p.fromPuny(p, u)
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
// This should be called on NonTransitional, according to the
|
||||||
|
// spec, but that currently does not have any effect. Use the
|
||||||
|
// original profile to preserve options.
|
||||||
|
err = p.validateLabel(u)
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
err = p.validateLabel(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if toASCII {
|
||||||
|
for labels.reset(); !labels.done(); labels.next() {
|
||||||
|
label := labels.label()
|
||||||
|
if !ascii(label) {
|
||||||
|
a, err2 := encode(acePrefix, label)
|
||||||
|
if err == nil {
|
||||||
|
err = err2
|
||||||
|
}
|
||||||
|
label = a
|
||||||
|
labels.set(a)
|
||||||
|
}
|
||||||
|
n := len(label)
|
||||||
|
if p.verifyDNSLength && err == nil && (n == 0 || n > 63) {
|
||||||
|
err = &labelError{label, "A4"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s = labels.result()
|
||||||
|
if toASCII && p.verifyDNSLength && err == nil {
|
||||||
|
// Compute the length of the domain name minus the root label and its dot.
|
||||||
|
n := len(s)
|
||||||
|
if n > 0 && s[n-1] == '.' {
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
if len(s) < 1 || n > 253 {
|
||||||
|
err = &labelError{s, "A4"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalize(p *Profile, s string) (string, error) {
|
||||||
|
return norm.NFC.String(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateRegistration(p *Profile, s string) (string, error) {
|
||||||
|
if !norm.NFC.IsNormalString(s) {
|
||||||
|
return s, &labelError{s, "V1"}
|
||||||
|
}
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
v, sz := trie.lookupString(s[i:])
|
||||||
|
// Copy bytes not copied so far.
|
||||||
|
switch p.simplify(info(v).category()) {
|
||||||
|
// TODO: handle the NV8 defined in the Unicode idna data set to allow
|
||||||
|
// for strict conformance to IDNA2008.
|
||||||
|
case valid, deviation:
|
||||||
|
case disallowed, mapped, unknown, ignored:
|
||||||
|
r, _ := utf8.DecodeRuneInString(s[i:])
|
||||||
|
return s, runeError(r)
|
||||||
|
}
|
||||||
|
i += sz
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateAndMap(p *Profile, s string) (string, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
b []byte
|
||||||
|
k int
|
||||||
|
)
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
v, sz := trie.lookupString(s[i:])
|
||||||
|
start := i
|
||||||
|
i += sz
|
||||||
|
// Copy bytes not copied so far.
|
||||||
|
switch p.simplify(info(v).category()) {
|
||||||
|
case valid:
|
||||||
|
continue
|
||||||
|
case disallowed:
|
||||||
|
if err == nil {
|
||||||
|
r, _ := utf8.DecodeRuneInString(s[start:])
|
||||||
|
err = runeError(r)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
case mapped, deviation:
|
||||||
|
b = append(b, s[k:start]...)
|
||||||
|
b = info(v).appendMapping(b, s[start:i])
|
||||||
|
case ignored:
|
||||||
|
b = append(b, s[k:start]...)
|
||||||
|
// drop the rune
|
||||||
|
case unknown:
|
||||||
|
b = append(b, s[k:start]...)
|
||||||
|
b = append(b, "\ufffd"...)
|
||||||
|
}
|
||||||
|
k = i
|
||||||
|
}
|
||||||
|
if k == 0 {
|
||||||
|
// No changes so far.
|
||||||
|
s = norm.NFC.String(s)
|
||||||
|
} else {
|
||||||
|
b = append(b, s[k:]...)
|
||||||
|
if norm.NFC.QuickSpan(b) != len(b) {
|
||||||
|
b = norm.NFC.Bytes(b)
|
||||||
|
}
|
||||||
|
// TODO: the punycode converters require strings as input.
|
||||||
|
s = string(b)
|
||||||
|
}
|
||||||
|
return s, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// A labelIter allows iterating over domain name labels.
|
||||||
|
type labelIter struct {
|
||||||
|
orig string
|
||||||
|
slice []string
|
||||||
|
curStart int
|
||||||
|
curEnd int
|
||||||
|
i int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *labelIter) reset() {
|
||||||
|
l.curStart = 0
|
||||||
|
l.curEnd = 0
|
||||||
|
l.i = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *labelIter) done() bool {
|
||||||
|
return l.curStart >= len(l.orig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *labelIter) result() string {
|
||||||
|
if l.slice != nil {
|
||||||
|
return strings.Join(l.slice, ".")
|
||||||
|
}
|
||||||
|
return l.orig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *labelIter) label() string {
|
||||||
|
if l.slice != nil {
|
||||||
|
return l.slice[l.i]
|
||||||
|
}
|
||||||
|
p := strings.IndexByte(l.orig[l.curStart:], '.')
|
||||||
|
l.curEnd = l.curStart + p
|
||||||
|
if p == -1 {
|
||||||
|
l.curEnd = len(l.orig)
|
||||||
|
}
|
||||||
|
return l.orig[l.curStart:l.curEnd]
|
||||||
|
}
|
||||||
|
|
||||||
|
// next sets the value to the next label. It skips the last label if it is empty.
|
||||||
|
func (l *labelIter) next() {
|
||||||
|
l.i++
|
||||||
|
if l.slice != nil {
|
||||||
|
if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" {
|
||||||
|
l.curStart = len(l.orig)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
l.curStart = l.curEnd + 1
|
||||||
|
if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' {
|
||||||
|
l.curStart = len(l.orig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *labelIter) set(s string) {
|
||||||
|
if l.slice == nil {
|
||||||
|
l.slice = strings.Split(l.orig, ".")
|
||||||
|
}
|
||||||
|
l.slice[l.i] = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// acePrefix is the ASCII Compatible Encoding prefix.
|
||||||
|
const acePrefix = "xn--"
|
||||||
|
|
||||||
|
func (p *Profile) simplify(cat category) category {
|
||||||
|
switch cat {
|
||||||
|
case disallowedSTD3Mapped:
|
||||||
|
if p.useSTD3Rules {
|
||||||
|
cat = disallowed
|
||||||
|
} else {
|
||||||
|
cat = mapped
|
||||||
|
}
|
||||||
|
case disallowedSTD3Valid:
|
||||||
|
if p.useSTD3Rules {
|
||||||
|
cat = disallowed
|
||||||
|
} else {
|
||||||
|
cat = valid
|
||||||
|
}
|
||||||
|
case deviation:
|
||||||
|
if !p.transitional {
|
||||||
|
cat = valid
|
||||||
|
}
|
||||||
|
case validNV8, validXV8:
|
||||||
|
// TODO: handle V2008
|
||||||
|
cat = valid
|
||||||
|
}
|
||||||
|
return cat
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateFromPunycode(p *Profile, s string) error {
|
||||||
|
if !norm.NFC.IsNormalString(s) {
|
||||||
|
return &labelError{s, "V1"}
|
||||||
|
}
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
v, sz := trie.lookupString(s[i:])
|
||||||
|
if c := p.simplify(info(v).category()); c != valid && c != deviation {
|
||||||
|
return &labelError{s, "V6"}
|
||||||
|
}
|
||||||
|
i += sz
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
zwnj = "\u200c"
|
||||||
|
zwj = "\u200d"
|
||||||
|
)
|
||||||
|
|
||||||
|
type joinState int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
stateStart joinState = iota
|
||||||
|
stateVirama
|
||||||
|
stateBefore
|
||||||
|
stateBeforeVirama
|
||||||
|
stateAfter
|
||||||
|
stateFAIL
|
||||||
|
)
|
||||||
|
|
||||||
|
var joinStates = [][numJoinTypes]joinState{
|
||||||
|
stateStart: {
|
||||||
|
joiningL: stateBefore,
|
||||||
|
joiningD: stateBefore,
|
||||||
|
joinZWNJ: stateFAIL,
|
||||||
|
joinZWJ: stateFAIL,
|
||||||
|
joinVirama: stateVirama,
|
||||||
|
},
|
||||||
|
stateVirama: {
|
||||||
|
joiningL: stateBefore,
|
||||||
|
joiningD: stateBefore,
|
||||||
|
},
|
||||||
|
stateBefore: {
|
||||||
|
joiningL: stateBefore,
|
||||||
|
joiningD: stateBefore,
|
||||||
|
joiningT: stateBefore,
|
||||||
|
joinZWNJ: stateAfter,
|
||||||
|
joinZWJ: stateFAIL,
|
||||||
|
joinVirama: stateBeforeVirama,
|
||||||
|
},
|
||||||
|
stateBeforeVirama: {
|
||||||
|
joiningL: stateBefore,
|
||||||
|
joiningD: stateBefore,
|
||||||
|
joiningT: stateBefore,
|
||||||
|
},
|
||||||
|
stateAfter: {
|
||||||
|
joiningL: stateFAIL,
|
||||||
|
joiningD: stateBefore,
|
||||||
|
joiningT: stateAfter,
|
||||||
|
joiningR: stateStart,
|
||||||
|
joinZWNJ: stateFAIL,
|
||||||
|
joinZWJ: stateFAIL,
|
||||||
|
joinVirama: stateAfter, // no-op as we can't accept joiners here
|
||||||
|
},
|
||||||
|
stateFAIL: {
|
||||||
|
0: stateFAIL,
|
||||||
|
joiningL: stateFAIL,
|
||||||
|
joiningD: stateFAIL,
|
||||||
|
joiningT: stateFAIL,
|
||||||
|
joiningR: stateFAIL,
|
||||||
|
joinZWNJ: stateFAIL,
|
||||||
|
joinZWJ: stateFAIL,
|
||||||
|
joinVirama: stateFAIL,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are
|
||||||
|
// already implicitly satisfied by the overall implementation.
|
||||||
|
func (p *Profile) validateLabel(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
if p.verifyDNSLength {
|
||||||
|
return &labelError{s, "A4"}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if p.bidirule != nil && !p.bidirule(s) {
|
||||||
|
return &labelError{s, "B"}
|
||||||
|
}
|
||||||
|
if !p.validateLabels {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
trie := p.trie // p.validateLabels is only set if trie is set.
|
||||||
|
if len(s) > 4 && s[2] == '-' && s[3] == '-' {
|
||||||
|
return &labelError{s, "V2"}
|
||||||
|
}
|
||||||
|
if s[0] == '-' || s[len(s)-1] == '-' {
|
||||||
|
return &labelError{s, "V3"}
|
||||||
|
}
|
||||||
|
// TODO: merge the use of this in the trie.
|
||||||
|
v, sz := trie.lookupString(s)
|
||||||
|
x := info(v)
|
||||||
|
if x.isModifier() {
|
||||||
|
return &labelError{s, "V5"}
|
||||||
|
}
|
||||||
|
// Quickly return in the absence of zero-width (non) joiners.
|
||||||
|
if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
st := stateStart
|
||||||
|
for i := 0; ; {
|
||||||
|
jt := x.joinType()
|
||||||
|
if s[i:i+sz] == zwj {
|
||||||
|
jt = joinZWJ
|
||||||
|
} else if s[i:i+sz] == zwnj {
|
||||||
|
jt = joinZWNJ
|
||||||
|
}
|
||||||
|
st = joinStates[st][jt]
|
||||||
|
if x.isViramaModifier() {
|
||||||
|
st = joinStates[st][joinVirama]
|
||||||
|
}
|
||||||
|
if i += sz; i == len(s) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v, sz = trie.lookupString(s[i:])
|
||||||
|
x = info(v)
|
||||||
|
}
|
||||||
|
if st == stateFAIL || st == stateAfter {
|
||||||
|
return &labelError{s, "C"}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ascii(s string) bool {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] >= utf8.RuneSelf {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
203
vendor/golang.org/x/net/idna/punycode.go
generated
vendored
Normal file
203
vendor/golang.org/x/net/idna/punycode.go
generated
vendored
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||||
|
|
||||||
|
// Copyright 2016 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 idna
|
||||||
|
|
||||||
|
// This file implements the Punycode algorithm from RFC 3492.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These parameter values are specified in section 5.
|
||||||
|
//
|
||||||
|
// All computation is done with int32s, so that overflow behavior is identical
|
||||||
|
// regardless of whether int is 32-bit or 64-bit.
|
||||||
|
const (
|
||||||
|
base int32 = 36
|
||||||
|
damp int32 = 700
|
||||||
|
initialBias int32 = 72
|
||||||
|
initialN int32 = 128
|
||||||
|
skew int32 = 38
|
||||||
|
tmax int32 = 26
|
||||||
|
tmin int32 = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func punyError(s string) error { return &labelError{s, "A3"} }
|
||||||
|
|
||||||
|
// decode decodes a string as specified in section 6.2.
|
||||||
|
func decode(encoded string) (string, error) {
|
||||||
|
if encoded == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
pos := 1 + strings.LastIndex(encoded, "-")
|
||||||
|
if pos == 1 {
|
||||||
|
return "", punyError(encoded)
|
||||||
|
}
|
||||||
|
if pos == len(encoded) {
|
||||||
|
return encoded[:len(encoded)-1], nil
|
||||||
|
}
|
||||||
|
output := make([]rune, 0, len(encoded))
|
||||||
|
if pos != 0 {
|
||||||
|
for _, r := range encoded[:pos-1] {
|
||||||
|
output = append(output, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i, n, bias := int32(0), initialN, initialBias
|
||||||
|
for pos < len(encoded) {
|
||||||
|
oldI, w := i, int32(1)
|
||||||
|
for k := base; ; k += base {
|
||||||
|
if pos == len(encoded) {
|
||||||
|
return "", punyError(encoded)
|
||||||
|
}
|
||||||
|
digit, ok := decodeDigit(encoded[pos])
|
||||||
|
if !ok {
|
||||||
|
return "", punyError(encoded)
|
||||||
|
}
|
||||||
|
pos++
|
||||||
|
i += digit * w
|
||||||
|
if i < 0 {
|
||||||
|
return "", punyError(encoded)
|
||||||
|
}
|
||||||
|
t := k - bias
|
||||||
|
if t < tmin {
|
||||||
|
t = tmin
|
||||||
|
} else if t > tmax {
|
||||||
|
t = tmax
|
||||||
|
}
|
||||||
|
if digit < t {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
w *= base - t
|
||||||
|
if w >= math.MaxInt32/base {
|
||||||
|
return "", punyError(encoded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x := int32(len(output) + 1)
|
||||||
|
bias = adapt(i-oldI, x, oldI == 0)
|
||||||
|
n += i / x
|
||||||
|
i %= x
|
||||||
|
if n > utf8.MaxRune || len(output) >= 1024 {
|
||||||
|
return "", punyError(encoded)
|
||||||
|
}
|
||||||
|
output = append(output, 0)
|
||||||
|
copy(output[i+1:], output[i:])
|
||||||
|
output[i] = n
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return string(output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode encodes a string as specified in section 6.3 and prepends prefix to
|
||||||
|
// the result.
|
||||||
|
//
|
||||||
|
// The "while h < length(input)" line in the specification becomes "for
|
||||||
|
// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
|
||||||
|
func encode(prefix, s string) (string, error) {
|
||||||
|
output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
|
||||||
|
copy(output, prefix)
|
||||||
|
delta, n, bias := int32(0), initialN, initialBias
|
||||||
|
b, remaining := int32(0), int32(0)
|
||||||
|
for _, r := range s {
|
||||||
|
if r < 0x80 {
|
||||||
|
b++
|
||||||
|
output = append(output, byte(r))
|
||||||
|
} else {
|
||||||
|
remaining++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h := b
|
||||||
|
if b > 0 {
|
||||||
|
output = append(output, '-')
|
||||||
|
}
|
||||||
|
for remaining != 0 {
|
||||||
|
m := int32(0x7fffffff)
|
||||||
|
for _, r := range s {
|
||||||
|
if m > r && r >= n {
|
||||||
|
m = r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delta += (m - n) * (h + 1)
|
||||||
|
if delta < 0 {
|
||||||
|
return "", punyError(s)
|
||||||
|
}
|
||||||
|
n = m
|
||||||
|
for _, r := range s {
|
||||||
|
if r < n {
|
||||||
|
delta++
|
||||||
|
if delta < 0 {
|
||||||
|
return "", punyError(s)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r > n {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
q := delta
|
||||||
|
for k := base; ; k += base {
|
||||||
|
t := k - bias
|
||||||
|
if t < tmin {
|
||||||
|
t = tmin
|
||||||
|
} else if t > tmax {
|
||||||
|
t = tmax
|
||||||
|
}
|
||||||
|
if q < t {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
output = append(output, encodeDigit(t+(q-t)%(base-t)))
|
||||||
|
q = (q - t) / (base - t)
|
||||||
|
}
|
||||||
|
output = append(output, encodeDigit(q))
|
||||||
|
bias = adapt(delta, h+1, h == b)
|
||||||
|
delta = 0
|
||||||
|
h++
|
||||||
|
remaining--
|
||||||
|
}
|
||||||
|
delta++
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
return string(output), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeDigit(x byte) (digit int32, ok bool) {
|
||||||
|
switch {
|
||||||
|
case '0' <= x && x <= '9':
|
||||||
|
return int32(x - ('0' - 26)), true
|
||||||
|
case 'A' <= x && x <= 'Z':
|
||||||
|
return int32(x - 'A'), true
|
||||||
|
case 'a' <= x && x <= 'z':
|
||||||
|
return int32(x - 'a'), true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeDigit(digit int32) byte {
|
||||||
|
switch {
|
||||||
|
case 0 <= digit && digit < 26:
|
||||||
|
return byte(digit + 'a')
|
||||||
|
case 26 <= digit && digit < 36:
|
||||||
|
return byte(digit + ('0' - 26))
|
||||||
|
}
|
||||||
|
panic("idna: internal error in punycode encoding")
|
||||||
|
}
|
||||||
|
|
||||||
|
// adapt is the bias adaptation function specified in section 6.1.
|
||||||
|
func adapt(delta, numPoints int32, firstTime bool) int32 {
|
||||||
|
if firstTime {
|
||||||
|
delta /= damp
|
||||||
|
} else {
|
||||||
|
delta /= 2
|
||||||
|
}
|
||||||
|
delta += delta / numPoints
|
||||||
|
k := int32(0)
|
||||||
|
for delta > ((base-tmin)*tmax)/2 {
|
||||||
|
delta /= base - tmin
|
||||||
|
k += base
|
||||||
|
}
|
||||||
|
return k + (base-tmin+1)*delta/(delta+skew)
|
||||||
|
}
|
4477
vendor/golang.org/x/net/idna/tables.go
generated
vendored
Normal file
4477
vendor/golang.org/x/net/idna/tables.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
72
vendor/golang.org/x/net/idna/trie.go
generated
vendored
Normal file
72
vendor/golang.org/x/net/idna/trie.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||||
|
|
||||||
|
// Copyright 2016 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 idna
|
||||||
|
|
||||||
|
// appendMapping appends the mapping for the respective rune. isMapped must be
|
||||||
|
// true. A mapping is a categorization of a rune as defined in UTS #46.
|
||||||
|
func (c info) appendMapping(b []byte, s string) []byte {
|
||||||
|
index := int(c >> indexShift)
|
||||||
|
if c&xorBit == 0 {
|
||||||
|
s := mappings[index:]
|
||||||
|
return append(b, s[1:s[0]+1]...)
|
||||||
|
}
|
||||||
|
b = append(b, s...)
|
||||||
|
if c&inlineXOR == inlineXOR {
|
||||||
|
// TODO: support and handle two-byte inline masks
|
||||||
|
b[len(b)-1] ^= byte(index)
|
||||||
|
} else {
|
||||||
|
for p := len(b) - int(xorData[index]); p < len(b); p++ {
|
||||||
|
index++
|
||||||
|
b[p] ^= xorData[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sparse block handling code.
|
||||||
|
|
||||||
|
type valueRange struct {
|
||||||
|
value uint16 // header: value:stride
|
||||||
|
lo, hi byte // header: lo:n
|
||||||
|
}
|
||||||
|
|
||||||
|
type sparseBlocks struct {
|
||||||
|
values []valueRange
|
||||||
|
offset []uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
var idnaSparse = sparseBlocks{
|
||||||
|
values: idnaSparseValues[:],
|
||||||
|
offset: idnaSparseOffset[:],
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't use newIdnaTrie to avoid unconditional linking in of the table.
|
||||||
|
var trie = &idnaTrie{}
|
||||||
|
|
||||||
|
// lookup determines the type of block n and looks up the value for b.
|
||||||
|
// For n < t.cutoff, the block is a simple lookup table. Otherwise, the block
|
||||||
|
// is a list of ranges with an accompanying value. Given a matching range r,
|
||||||
|
// the value for b is by r.value + (b - r.lo) * stride.
|
||||||
|
func (t *sparseBlocks) lookup(n uint32, b byte) uint16 {
|
||||||
|
offset := t.offset[n]
|
||||||
|
header := t.values[offset]
|
||||||
|
lo := offset + 1
|
||||||
|
hi := lo + uint16(header.lo)
|
||||||
|
for lo < hi {
|
||||||
|
m := lo + (hi-lo)/2
|
||||||
|
r := t.values[m]
|
||||||
|
if r.lo <= b && b <= r.hi {
|
||||||
|
return r.value + uint16(b-r.lo)*header.value
|
||||||
|
}
|
||||||
|
if b < r.lo {
|
||||||
|
hi = m
|
||||||
|
} else {
|
||||||
|
lo = m + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
114
vendor/golang.org/x/net/idna/trieval.go
generated
vendored
Normal file
114
vendor/golang.org/x/net/idna/trieval.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
||||||
|
|
||||||
|
package idna
|
||||||
|
|
||||||
|
// This file contains definitions for interpreting the trie value of the idna
|
||||||
|
// trie generated by "go run gen*.go". It is shared by both the generator
|
||||||
|
// program and the resultant package. Sharing is achieved by the generator
|
||||||
|
// copying gen_trieval.go to trieval.go and changing what's above this comment.
|
||||||
|
|
||||||
|
// info holds information from the IDNA mapping table for a single rune. It is
|
||||||
|
// the value returned by a trie lookup. In most cases, all information fits in
|
||||||
|
// a 16-bit value. For mappings, this value may contain an index into a slice
|
||||||
|
// with the mapped string. Such mappings can consist of the actual mapped value
|
||||||
|
// or an XOR pattern to be applied to the bytes of the UTF8 encoding of the
|
||||||
|
// input rune. This technique is used by the cases packages and reduces the
|
||||||
|
// table size significantly.
|
||||||
|
//
|
||||||
|
// The per-rune values have the following format:
|
||||||
|
//
|
||||||
|
// if mapped {
|
||||||
|
// if inlinedXOR {
|
||||||
|
// 15..13 inline XOR marker
|
||||||
|
// 12..11 unused
|
||||||
|
// 10..3 inline XOR mask
|
||||||
|
// } else {
|
||||||
|
// 15..3 index into xor or mapping table
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// 15..13 unused
|
||||||
|
// 12 modifier (including virama)
|
||||||
|
// 11 virama modifier
|
||||||
|
// 10..8 joining type
|
||||||
|
// 7..3 category type
|
||||||
|
// }
|
||||||
|
// 2 use xor pattern
|
||||||
|
// 1..0 mapped category
|
||||||
|
//
|
||||||
|
// See the definitions below for a more detailed description of the various
|
||||||
|
// bits.
|
||||||
|
type info uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
catSmallMask = 0x3
|
||||||
|
catBigMask = 0xF8
|
||||||
|
indexShift = 3
|
||||||
|
xorBit = 0x4 // interpret the index as an xor pattern
|
||||||
|
inlineXOR = 0xE000 // These bits are set if the XOR pattern is inlined.
|
||||||
|
|
||||||
|
joinShift = 8
|
||||||
|
joinMask = 0x07
|
||||||
|
|
||||||
|
viramaModifier = 0x0800
|
||||||
|
modifier = 0x1000
|
||||||
|
)
|
||||||
|
|
||||||
|
// A category corresponds to a category defined in the IDNA mapping table.
|
||||||
|
type category uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
unknown category = 0 // not defined currently in unicode.
|
||||||
|
mapped category = 1
|
||||||
|
disallowedSTD3Mapped category = 2
|
||||||
|
deviation category = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
valid category = 0x08
|
||||||
|
validNV8 category = 0x18
|
||||||
|
validXV8 category = 0x28
|
||||||
|
disallowed category = 0x40
|
||||||
|
disallowedSTD3Valid category = 0x80
|
||||||
|
ignored category = 0xC0
|
||||||
|
)
|
||||||
|
|
||||||
|
// join types and additional rune information
|
||||||
|
const (
|
||||||
|
joiningL = (iota + 1)
|
||||||
|
joiningD
|
||||||
|
joiningT
|
||||||
|
joiningR
|
||||||
|
|
||||||
|
//the following types are derived during processing
|
||||||
|
joinZWJ
|
||||||
|
joinZWNJ
|
||||||
|
joinVirama
|
||||||
|
numJoinTypes
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c info) isMapped() bool {
|
||||||
|
return c&0x3 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c info) category() category {
|
||||||
|
small := c & catSmallMask
|
||||||
|
if small != 0 {
|
||||||
|
return category(small)
|
||||||
|
}
|
||||||
|
return category(c & catBigMask)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c info) joinType() info {
|
||||||
|
if c.isMapped() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (c >> joinShift) & joinMask
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c info) isModifier() bool {
|
||||||
|
return c&(modifier|catSmallMask) == modifier
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c info) isViramaModifier() bool {
|
||||||
|
return c&(viramaModifier|catSmallMask) == viramaModifier
|
||||||
|
}
|
525
vendor/golang.org/x/net/internal/timeseries/timeseries.go
generated
vendored
Normal file
525
vendor/golang.org/x/net/internal/timeseries/timeseries.go
generated
vendored
Normal file
|
@ -0,0 +1,525 @@
|
||||||
|
// Copyright 2015 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 timeseries implements a time series structure for stats collection.
|
||||||
|
package timeseries
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
timeSeriesNumBuckets = 64
|
||||||
|
minuteHourSeriesNumBuckets = 60
|
||||||
|
)
|
||||||
|
|
||||||
|
var timeSeriesResolutions = []time.Duration{
|
||||||
|
1 * time.Second,
|
||||||
|
10 * time.Second,
|
||||||
|
1 * time.Minute,
|
||||||
|
10 * time.Minute,
|
||||||
|
1 * time.Hour,
|
||||||
|
6 * time.Hour,
|
||||||
|
24 * time.Hour, // 1 day
|
||||||
|
7 * 24 * time.Hour, // 1 week
|
||||||
|
4 * 7 * 24 * time.Hour, // 4 weeks
|
||||||
|
16 * 7 * 24 * time.Hour, // 16 weeks
|
||||||
|
}
|
||||||
|
|
||||||
|
var minuteHourSeriesResolutions = []time.Duration{
|
||||||
|
1 * time.Second,
|
||||||
|
1 * time.Minute,
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Observable is a kind of data that can be aggregated in a time series.
|
||||||
|
type Observable interface {
|
||||||
|
Multiply(ratio float64) // Multiplies the data in self by a given ratio
|
||||||
|
Add(other Observable) // Adds the data from a different observation to self
|
||||||
|
Clear() // Clears the observation so it can be reused.
|
||||||
|
CopyFrom(other Observable) // Copies the contents of a given observation to self
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float attaches the methods of Observable to a float64.
|
||||||
|
type Float float64
|
||||||
|
|
||||||
|
// NewFloat returns a Float.
|
||||||
|
func NewFloat() Observable {
|
||||||
|
f := Float(0)
|
||||||
|
return &f
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the float as a string.
|
||||||
|
func (f *Float) String() string { return fmt.Sprintf("%g", f.Value()) }
|
||||||
|
|
||||||
|
// Value returns the float's value.
|
||||||
|
func (f *Float) Value() float64 { return float64(*f) }
|
||||||
|
|
||||||
|
func (f *Float) Multiply(ratio float64) { *f *= Float(ratio) }
|
||||||
|
|
||||||
|
func (f *Float) Add(other Observable) {
|
||||||
|
o := other.(*Float)
|
||||||
|
*f += *o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Float) Clear() { *f = 0 }
|
||||||
|
|
||||||
|
func (f *Float) CopyFrom(other Observable) {
|
||||||
|
o := other.(*Float)
|
||||||
|
*f = *o
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Clock tells the current time.
|
||||||
|
type Clock interface {
|
||||||
|
Time() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultClock int
|
||||||
|
|
||||||
|
var defaultClockInstance defaultClock
|
||||||
|
|
||||||
|
func (defaultClock) Time() time.Time { return time.Now() }
|
||||||
|
|
||||||
|
// Information kept per level. Each level consists of a circular list of
|
||||||
|
// observations. The start of the level may be derived from end and the
|
||||||
|
// len(buckets) * sizeInMillis.
|
||||||
|
type tsLevel struct {
|
||||||
|
oldest int // index to oldest bucketed Observable
|
||||||
|
newest int // index to newest bucketed Observable
|
||||||
|
end time.Time // end timestamp for this level
|
||||||
|
size time.Duration // duration of the bucketed Observable
|
||||||
|
buckets []Observable // collections of observations
|
||||||
|
provider func() Observable // used for creating new Observable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tsLevel) Clear() {
|
||||||
|
l.oldest = 0
|
||||||
|
l.newest = len(l.buckets) - 1
|
||||||
|
l.end = time.Time{}
|
||||||
|
for i := range l.buckets {
|
||||||
|
if l.buckets[i] != nil {
|
||||||
|
l.buckets[i].Clear()
|
||||||
|
l.buckets[i] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tsLevel) InitLevel(size time.Duration, numBuckets int, f func() Observable) {
|
||||||
|
l.size = size
|
||||||
|
l.provider = f
|
||||||
|
l.buckets = make([]Observable, numBuckets)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keeps a sequence of levels. Each level is responsible for storing data at
|
||||||
|
// a given resolution. For example, the first level stores data at a one
|
||||||
|
// minute resolution while the second level stores data at a one hour
|
||||||
|
// resolution.
|
||||||
|
|
||||||
|
// Each level is represented by a sequence of buckets. Each bucket spans an
|
||||||
|
// interval equal to the resolution of the level. New observations are added
|
||||||
|
// to the last bucket.
|
||||||
|
type timeSeries struct {
|
||||||
|
provider func() Observable // make more Observable
|
||||||
|
numBuckets int // number of buckets in each level
|
||||||
|
levels []*tsLevel // levels of bucketed Observable
|
||||||
|
lastAdd time.Time // time of last Observable tracked
|
||||||
|
total Observable // convenient aggregation of all Observable
|
||||||
|
clock Clock // Clock for getting current time
|
||||||
|
pending Observable // observations not yet bucketed
|
||||||
|
pendingTime time.Time // what time are we keeping in pending
|
||||||
|
dirty bool // if there are pending observations
|
||||||
|
}
|
||||||
|
|
||||||
|
// init initializes a level according to the supplied criteria.
|
||||||
|
func (ts *timeSeries) init(resolutions []time.Duration, f func() Observable, numBuckets int, clock Clock) {
|
||||||
|
ts.provider = f
|
||||||
|
ts.numBuckets = numBuckets
|
||||||
|
ts.clock = clock
|
||||||
|
ts.levels = make([]*tsLevel, len(resolutions))
|
||||||
|
|
||||||
|
for i := range resolutions {
|
||||||
|
if i > 0 && resolutions[i-1] >= resolutions[i] {
|
||||||
|
log.Print("timeseries: resolutions must be monotonically increasing")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
newLevel := new(tsLevel)
|
||||||
|
newLevel.InitLevel(resolutions[i], ts.numBuckets, ts.provider)
|
||||||
|
ts.levels[i] = newLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear removes all observations from the time series.
|
||||||
|
func (ts *timeSeries) Clear() {
|
||||||
|
ts.lastAdd = time.Time{}
|
||||||
|
ts.total = ts.resetObservation(ts.total)
|
||||||
|
ts.pending = ts.resetObservation(ts.pending)
|
||||||
|
ts.pendingTime = time.Time{}
|
||||||
|
ts.dirty = false
|
||||||
|
|
||||||
|
for i := range ts.levels {
|
||||||
|
ts.levels[i].Clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add records an observation at the current time.
|
||||||
|
func (ts *timeSeries) Add(observation Observable) {
|
||||||
|
ts.AddWithTime(observation, ts.clock.Time())
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddWithTime records an observation at the specified time.
|
||||||
|
func (ts *timeSeries) AddWithTime(observation Observable, t time.Time) {
|
||||||
|
|
||||||
|
smallBucketDuration := ts.levels[0].size
|
||||||
|
|
||||||
|
if t.After(ts.lastAdd) {
|
||||||
|
ts.lastAdd = t
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.After(ts.pendingTime) {
|
||||||
|
ts.advance(t)
|
||||||
|
ts.mergePendingUpdates()
|
||||||
|
ts.pendingTime = ts.levels[0].end
|
||||||
|
ts.pending.CopyFrom(observation)
|
||||||
|
ts.dirty = true
|
||||||
|
} else if t.After(ts.pendingTime.Add(-1 * smallBucketDuration)) {
|
||||||
|
// The observation is close enough to go into the pending bucket.
|
||||||
|
// This compensates for clock skewing and small scheduling delays
|
||||||
|
// by letting the update stay in the fast path.
|
||||||
|
ts.pending.Add(observation)
|
||||||
|
ts.dirty = true
|
||||||
|
} else {
|
||||||
|
ts.mergeValue(observation, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergeValue inserts the observation at the specified time in the past into all levels.
|
||||||
|
func (ts *timeSeries) mergeValue(observation Observable, t time.Time) {
|
||||||
|
for _, level := range ts.levels {
|
||||||
|
index := (ts.numBuckets - 1) - int(level.end.Sub(t)/level.size)
|
||||||
|
if 0 <= index && index < ts.numBuckets {
|
||||||
|
bucketNumber := (level.oldest + index) % ts.numBuckets
|
||||||
|
if level.buckets[bucketNumber] == nil {
|
||||||
|
level.buckets[bucketNumber] = level.provider()
|
||||||
|
}
|
||||||
|
level.buckets[bucketNumber].Add(observation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ts.total.Add(observation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergePendingUpdates applies the pending updates into all levels.
|
||||||
|
func (ts *timeSeries) mergePendingUpdates() {
|
||||||
|
if ts.dirty {
|
||||||
|
ts.mergeValue(ts.pending, ts.pendingTime)
|
||||||
|
ts.pending = ts.resetObservation(ts.pending)
|
||||||
|
ts.dirty = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// advance cycles the buckets at each level until the latest bucket in
|
||||||
|
// each level can hold the time specified.
|
||||||
|
func (ts *timeSeries) advance(t time.Time) {
|
||||||
|
if !t.After(ts.levels[0].end) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; i < len(ts.levels); i++ {
|
||||||
|
level := ts.levels[i]
|
||||||
|
if !level.end.Before(t) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the time is sufficiently far, just clear the level and advance
|
||||||
|
// directly.
|
||||||
|
if !t.Before(level.end.Add(level.size * time.Duration(ts.numBuckets))) {
|
||||||
|
for _, b := range level.buckets {
|
||||||
|
ts.resetObservation(b)
|
||||||
|
}
|
||||||
|
level.end = time.Unix(0, (t.UnixNano()/level.size.Nanoseconds())*level.size.Nanoseconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
for t.After(level.end) {
|
||||||
|
level.end = level.end.Add(level.size)
|
||||||
|
level.newest = level.oldest
|
||||||
|
level.oldest = (level.oldest + 1) % ts.numBuckets
|
||||||
|
ts.resetObservation(level.buckets[level.newest])
|
||||||
|
}
|
||||||
|
|
||||||
|
t = level.end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latest returns the sum of the num latest buckets from the level.
|
||||||
|
func (ts *timeSeries) Latest(level, num int) Observable {
|
||||||
|
now := ts.clock.Time()
|
||||||
|
if ts.levels[0].end.Before(now) {
|
||||||
|
ts.advance(now)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.mergePendingUpdates()
|
||||||
|
|
||||||
|
result := ts.provider()
|
||||||
|
l := ts.levels[level]
|
||||||
|
index := l.newest
|
||||||
|
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
if l.buckets[index] != nil {
|
||||||
|
result.Add(l.buckets[index])
|
||||||
|
}
|
||||||
|
if index == 0 {
|
||||||
|
index = ts.numBuckets
|
||||||
|
}
|
||||||
|
index--
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// LatestBuckets returns a copy of the num latest buckets from level.
|
||||||
|
func (ts *timeSeries) LatestBuckets(level, num int) []Observable {
|
||||||
|
if level < 0 || level > len(ts.levels) {
|
||||||
|
log.Print("timeseries: bad level argument: ", level)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if num < 0 || num >= ts.numBuckets {
|
||||||
|
log.Print("timeseries: bad num argument: ", num)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
results := make([]Observable, num)
|
||||||
|
now := ts.clock.Time()
|
||||||
|
if ts.levels[0].end.Before(now) {
|
||||||
|
ts.advance(now)
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.mergePendingUpdates()
|
||||||
|
|
||||||
|
l := ts.levels[level]
|
||||||
|
index := l.newest
|
||||||
|
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
result := ts.provider()
|
||||||
|
results[i] = result
|
||||||
|
if l.buckets[index] != nil {
|
||||||
|
result.CopyFrom(l.buckets[index])
|
||||||
|
}
|
||||||
|
|
||||||
|
if index == 0 {
|
||||||
|
index = ts.numBuckets
|
||||||
|
}
|
||||||
|
index -= 1
|
||||||
|
}
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScaleBy updates observations by scaling by factor.
|
||||||
|
func (ts *timeSeries) ScaleBy(factor float64) {
|
||||||
|
for _, l := range ts.levels {
|
||||||
|
for i := 0; i < ts.numBuckets; i++ {
|
||||||
|
l.buckets[i].Multiply(factor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.total.Multiply(factor)
|
||||||
|
ts.pending.Multiply(factor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range returns the sum of observations added over the specified time range.
|
||||||
|
// If start or finish times don't fall on bucket boundaries of the same
|
||||||
|
// level, then return values are approximate answers.
|
||||||
|
func (ts *timeSeries) Range(start, finish time.Time) Observable {
|
||||||
|
return ts.ComputeRange(start, finish, 1)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recent returns the sum of observations from the last delta.
|
||||||
|
func (ts *timeSeries) Recent(delta time.Duration) Observable {
|
||||||
|
now := ts.clock.Time()
|
||||||
|
return ts.Range(now.Add(-delta), now)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total returns the total of all observations.
|
||||||
|
func (ts *timeSeries) Total() Observable {
|
||||||
|
ts.mergePendingUpdates()
|
||||||
|
return ts.total
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputeRange computes a specified number of values into a slice using
|
||||||
|
// the observations recorded over the specified time period. The return
|
||||||
|
// values are approximate if the start or finish times don't fall on the
|
||||||
|
// bucket boundaries at the same level or if the number of buckets spanning
|
||||||
|
// the range is not an integral multiple of num.
|
||||||
|
func (ts *timeSeries) ComputeRange(start, finish time.Time, num int) []Observable {
|
||||||
|
if start.After(finish) {
|
||||||
|
log.Printf("timeseries: start > finish, %v>%v", start, finish)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if num < 0 {
|
||||||
|
log.Printf("timeseries: num < 0, %v", num)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
results := make([]Observable, num)
|
||||||
|
|
||||||
|
for _, l := range ts.levels {
|
||||||
|
if !start.Before(l.end.Add(-l.size * time.Duration(ts.numBuckets))) {
|
||||||
|
ts.extract(l, start, finish, num, results)
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed to find a level that covers the desired range. So just
|
||||||
|
// extract from the last level, even if it doesn't cover the entire
|
||||||
|
// desired range.
|
||||||
|
ts.extract(ts.levels[len(ts.levels)-1], start, finish, num, results)
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecentList returns the specified number of values in slice over the most
|
||||||
|
// recent time period of the specified range.
|
||||||
|
func (ts *timeSeries) RecentList(delta time.Duration, num int) []Observable {
|
||||||
|
if delta < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
now := ts.clock.Time()
|
||||||
|
return ts.ComputeRange(now.Add(-delta), now, num)
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract returns a slice of specified number of observations from a given
|
||||||
|
// level over a given range.
|
||||||
|
func (ts *timeSeries) extract(l *tsLevel, start, finish time.Time, num int, results []Observable) {
|
||||||
|
ts.mergePendingUpdates()
|
||||||
|
|
||||||
|
srcInterval := l.size
|
||||||
|
dstInterval := finish.Sub(start) / time.Duration(num)
|
||||||
|
dstStart := start
|
||||||
|
srcStart := l.end.Add(-srcInterval * time.Duration(ts.numBuckets))
|
||||||
|
|
||||||
|
srcIndex := 0
|
||||||
|
|
||||||
|
// Where should scanning start?
|
||||||
|
if dstStart.After(srcStart) {
|
||||||
|
advance := dstStart.Sub(srcStart) / srcInterval
|
||||||
|
srcIndex += int(advance)
|
||||||
|
srcStart = srcStart.Add(advance * srcInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The i'th value is computed as show below.
|
||||||
|
// interval = (finish/start)/num
|
||||||
|
// i'th value = sum of observation in range
|
||||||
|
// [ start + i * interval,
|
||||||
|
// start + (i + 1) * interval )
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
results[i] = ts.resetObservation(results[i])
|
||||||
|
dstEnd := dstStart.Add(dstInterval)
|
||||||
|
for srcIndex < ts.numBuckets && srcStart.Before(dstEnd) {
|
||||||
|
srcEnd := srcStart.Add(srcInterval)
|
||||||
|
if srcEnd.After(ts.lastAdd) {
|
||||||
|
srcEnd = ts.lastAdd
|
||||||
|
}
|
||||||
|
|
||||||
|
if !srcEnd.Before(dstStart) {
|
||||||
|
srcValue := l.buckets[(srcIndex+l.oldest)%ts.numBuckets]
|
||||||
|
if !srcStart.Before(dstStart) && !srcEnd.After(dstEnd) {
|
||||||
|
// dst completely contains src.
|
||||||
|
if srcValue != nil {
|
||||||
|
results[i].Add(srcValue)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// dst partially overlaps src.
|
||||||
|
overlapStart := maxTime(srcStart, dstStart)
|
||||||
|
overlapEnd := minTime(srcEnd, dstEnd)
|
||||||
|
base := srcEnd.Sub(srcStart)
|
||||||
|
fraction := overlapEnd.Sub(overlapStart).Seconds() / base.Seconds()
|
||||||
|
|
||||||
|
used := ts.provider()
|
||||||
|
if srcValue != nil {
|
||||||
|
used.CopyFrom(srcValue)
|
||||||
|
}
|
||||||
|
used.Multiply(fraction)
|
||||||
|
results[i].Add(used)
|
||||||
|
}
|
||||||
|
|
||||||
|
if srcEnd.After(dstEnd) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srcIndex++
|
||||||
|
srcStart = srcStart.Add(srcInterval)
|
||||||
|
}
|
||||||
|
dstStart = dstStart.Add(dstInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resetObservation clears the content so the struct may be reused.
|
||||||
|
func (ts *timeSeries) resetObservation(observation Observable) Observable {
|
||||||
|
if observation == nil {
|
||||||
|
observation = ts.provider()
|
||||||
|
} else {
|
||||||
|
observation.Clear()
|
||||||
|
}
|
||||||
|
return observation
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeSeries tracks data at granularities from 1 second to 16 weeks.
|
||||||
|
type TimeSeries struct {
|
||||||
|
timeSeries
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTimeSeries creates a new TimeSeries using the function provided for creating new Observable.
|
||||||
|
func NewTimeSeries(f func() Observable) *TimeSeries {
|
||||||
|
return NewTimeSeriesWithClock(f, defaultClockInstance)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTimeSeriesWithClock creates a new TimeSeries using the function provided for creating new Observable and the clock for
|
||||||
|
// assigning timestamps.
|
||||||
|
func NewTimeSeriesWithClock(f func() Observable, clock Clock) *TimeSeries {
|
||||||
|
ts := new(TimeSeries)
|
||||||
|
ts.timeSeries.init(timeSeriesResolutions, f, timeSeriesNumBuckets, clock)
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinuteHourSeries tracks data at granularities of 1 minute and 1 hour.
|
||||||
|
type MinuteHourSeries struct {
|
||||||
|
timeSeries
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMinuteHourSeries creates a new MinuteHourSeries using the function provided for creating new Observable.
|
||||||
|
func NewMinuteHourSeries(f func() Observable) *MinuteHourSeries {
|
||||||
|
return NewMinuteHourSeriesWithClock(f, defaultClockInstance)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMinuteHourSeriesWithClock creates a new MinuteHourSeries using the function provided for creating new Observable and the clock for
|
||||||
|
// assigning timestamps.
|
||||||
|
func NewMinuteHourSeriesWithClock(f func() Observable, clock Clock) *MinuteHourSeries {
|
||||||
|
ts := new(MinuteHourSeries)
|
||||||
|
ts.timeSeries.init(minuteHourSeriesResolutions, f,
|
||||||
|
minuteHourSeriesNumBuckets, clock)
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *MinuteHourSeries) Minute() Observable {
|
||||||
|
return ts.timeSeries.Latest(0, 60)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *MinuteHourSeries) Hour() Observable {
|
||||||
|
return ts.timeSeries.Latest(1, 60)
|
||||||
|
}
|
||||||
|
|
||||||
|
func minTime(a, b time.Time) time.Time {
|
||||||
|
if a.Before(b) {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxTime(a, b time.Time) time.Time {
|
||||||
|
if a.After(b) {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
351
vendor/golang.org/x/net/lex/httplex/httplex.go
generated
vendored
Normal file
351
vendor/golang.org/x/net/lex/httplex/httplex.go
generated
vendored
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
// Copyright 2016 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 httplex contains rules around lexical matters of various
|
||||||
|
// HTTP-related specifications.
|
||||||
|
//
|
||||||
|
// This package is shared by the standard library (which vendors it)
|
||||||
|
// and x/net/http2. It comes with no API stability promise.
|
||||||
|
package httplex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"golang.org/x/net/idna"
|
||||||
|
)
|
||||||
|
|
||||||
|
var isTokenTable = [127]bool{
|
||||||
|
'!': true,
|
||||||
|
'#': true,
|
||||||
|
'$': true,
|
||||||
|
'%': true,
|
||||||
|
'&': true,
|
||||||
|
'\'': true,
|
||||||
|
'*': true,
|
||||||
|
'+': true,
|
||||||
|
'-': true,
|
||||||
|
'.': true,
|
||||||
|
'0': true,
|
||||||
|
'1': true,
|
||||||
|
'2': true,
|
||||||
|
'3': true,
|
||||||
|
'4': true,
|
||||||
|
'5': true,
|
||||||
|
'6': true,
|
||||||
|
'7': true,
|
||||||
|
'8': true,
|
||||||
|
'9': true,
|
||||||
|
'A': true,
|
||||||
|
'B': true,
|
||||||
|
'C': true,
|
||||||
|
'D': true,
|
||||||
|
'E': true,
|
||||||
|
'F': true,
|
||||||
|
'G': true,
|
||||||
|
'H': true,
|
||||||
|
'I': true,
|
||||||
|
'J': true,
|
||||||
|
'K': true,
|
||||||
|
'L': true,
|
||||||
|
'M': true,
|
||||||
|
'N': true,
|
||||||
|
'O': true,
|
||||||
|
'P': true,
|
||||||
|
'Q': true,
|
||||||
|
'R': true,
|
||||||
|
'S': true,
|
||||||
|
'T': true,
|
||||||
|
'U': true,
|
||||||
|
'W': true,
|
||||||
|
'V': true,
|
||||||
|
'X': true,
|
||||||
|
'Y': true,
|
||||||
|
'Z': true,
|
||||||
|
'^': true,
|
||||||
|
'_': true,
|
||||||
|
'`': true,
|
||||||
|
'a': true,
|
||||||
|
'b': true,
|
||||||
|
'c': true,
|
||||||
|
'd': true,
|
||||||
|
'e': true,
|
||||||
|
'f': true,
|
||||||
|
'g': true,
|
||||||
|
'h': true,
|
||||||
|
'i': true,
|
||||||
|
'j': true,
|
||||||
|
'k': true,
|
||||||
|
'l': true,
|
||||||
|
'm': true,
|
||||||
|
'n': true,
|
||||||
|
'o': true,
|
||||||
|
'p': true,
|
||||||
|
'q': true,
|
||||||
|
'r': true,
|
||||||
|
's': true,
|
||||||
|
't': true,
|
||||||
|
'u': true,
|
||||||
|
'v': true,
|
||||||
|
'w': true,
|
||||||
|
'x': true,
|
||||||
|
'y': true,
|
||||||
|
'z': true,
|
||||||
|
'|': true,
|
||||||
|
'~': true,
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsTokenRune(r rune) bool {
|
||||||
|
i := int(r)
|
||||||
|
return i < len(isTokenTable) && isTokenTable[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotToken(r rune) bool {
|
||||||
|
return !IsTokenRune(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeaderValuesContainsToken reports whether any string in values
|
||||||
|
// contains the provided token, ASCII case-insensitively.
|
||||||
|
func HeaderValuesContainsToken(values []string, token string) bool {
|
||||||
|
for _, v := range values {
|
||||||
|
if headerValueContainsToken(v, token) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isOWS reports whether b is an optional whitespace byte, as defined
|
||||||
|
// by RFC 7230 section 3.2.3.
|
||||||
|
func isOWS(b byte) bool { return b == ' ' || b == '\t' }
|
||||||
|
|
||||||
|
// trimOWS returns x with all optional whitespace removes from the
|
||||||
|
// beginning and end.
|
||||||
|
func trimOWS(x string) string {
|
||||||
|
// TODO: consider using strings.Trim(x, " \t") instead,
|
||||||
|
// if and when it's fast enough. See issue 10292.
|
||||||
|
// But this ASCII-only code will probably always beat UTF-8
|
||||||
|
// aware code.
|
||||||
|
for len(x) > 0 && isOWS(x[0]) {
|
||||||
|
x = x[1:]
|
||||||
|
}
|
||||||
|
for len(x) > 0 && isOWS(x[len(x)-1]) {
|
||||||
|
x = x[:len(x)-1]
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// headerValueContainsToken reports whether v (assumed to be a
|
||||||
|
// 0#element, in the ABNF extension described in RFC 7230 section 7)
|
||||||
|
// contains token amongst its comma-separated tokens, ASCII
|
||||||
|
// case-insensitively.
|
||||||
|
func headerValueContainsToken(v string, token string) bool {
|
||||||
|
v = trimOWS(v)
|
||||||
|
if comma := strings.IndexByte(v, ','); comma != -1 {
|
||||||
|
return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
|
||||||
|
}
|
||||||
|
return tokenEqual(v, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lowerASCII returns the ASCII lowercase version of b.
|
||||||
|
func lowerASCII(b byte) byte {
|
||||||
|
if 'A' <= b && b <= 'Z' {
|
||||||
|
return b + ('a' - 'A')
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
|
||||||
|
func tokenEqual(t1, t2 string) bool {
|
||||||
|
if len(t1) != len(t2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i, b := range t1 {
|
||||||
|
if b >= utf8.RuneSelf {
|
||||||
|
// No UTF-8 or non-ASCII allowed in tokens.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// isLWS reports whether b is linear white space, according
|
||||||
|
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
|
||||||
|
// LWS = [CRLF] 1*( SP | HT )
|
||||||
|
func isLWS(b byte) bool { return b == ' ' || b == '\t' }
|
||||||
|
|
||||||
|
// isCTL reports whether b is a control byte, according
|
||||||
|
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
|
||||||
|
// CTL = <any US-ASCII control character
|
||||||
|
// (octets 0 - 31) and DEL (127)>
|
||||||
|
func isCTL(b byte) bool {
|
||||||
|
const del = 0x7f // a CTL
|
||||||
|
return b < ' ' || b == del
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name.
|
||||||
|
// HTTP/2 imposes the additional restriction that uppercase ASCII
|
||||||
|
// letters are not allowed.
|
||||||
|
//
|
||||||
|
// RFC 7230 says:
|
||||||
|
// header-field = field-name ":" OWS field-value OWS
|
||||||
|
// field-name = token
|
||||||
|
// token = 1*tchar
|
||||||
|
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
||||||
|
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
||||||
|
func ValidHeaderFieldName(v string) bool {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, r := range v {
|
||||||
|
if !IsTokenRune(r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidHostHeader reports whether h is a valid host header.
|
||||||
|
func ValidHostHeader(h string) bool {
|
||||||
|
// The latest spec is actually this:
|
||||||
|
//
|
||||||
|
// http://tools.ietf.org/html/rfc7230#section-5.4
|
||||||
|
// Host = uri-host [ ":" port ]
|
||||||
|
//
|
||||||
|
// Where uri-host is:
|
||||||
|
// http://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||||
|
//
|
||||||
|
// But we're going to be much more lenient for now and just
|
||||||
|
// search for any byte that's not a valid byte in any of those
|
||||||
|
// expressions.
|
||||||
|
for i := 0; i < len(h); i++ {
|
||||||
|
if !validHostByte[h[i]] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// See the validHostHeader comment.
|
||||||
|
var validHostByte = [256]bool{
|
||||||
|
'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
|
||||||
|
'8': true, '9': true,
|
||||||
|
|
||||||
|
'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
|
||||||
|
'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
|
||||||
|
'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
|
||||||
|
'y': true, 'z': true,
|
||||||
|
|
||||||
|
'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
|
||||||
|
'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
|
||||||
|
'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
|
||||||
|
'Y': true, 'Z': true,
|
||||||
|
|
||||||
|
'!': true, // sub-delims
|
||||||
|
'$': true, // sub-delims
|
||||||
|
'%': true, // pct-encoded (and used in IPv6 zones)
|
||||||
|
'&': true, // sub-delims
|
||||||
|
'(': true, // sub-delims
|
||||||
|
')': true, // sub-delims
|
||||||
|
'*': true, // sub-delims
|
||||||
|
'+': true, // sub-delims
|
||||||
|
',': true, // sub-delims
|
||||||
|
'-': true, // unreserved
|
||||||
|
'.': true, // unreserved
|
||||||
|
':': true, // IPv6address + Host expression's optional port
|
||||||
|
';': true, // sub-delims
|
||||||
|
'=': true, // sub-delims
|
||||||
|
'[': true,
|
||||||
|
'\'': true, // sub-delims
|
||||||
|
']': true,
|
||||||
|
'_': true, // unreserved
|
||||||
|
'~': true, // unreserved
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidHeaderFieldValue reports whether v is a valid "field-value" according to
|
||||||
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
|
||||||
|
//
|
||||||
|
// message-header = field-name ":" [ field-value ]
|
||||||
|
// field-value = *( field-content | LWS )
|
||||||
|
// field-content = <the OCTETs making up the field-value
|
||||||
|
// and consisting of either *TEXT or combinations
|
||||||
|
// of token, separators, and quoted-string>
|
||||||
|
//
|
||||||
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
|
||||||
|
//
|
||||||
|
// TEXT = <any OCTET except CTLs,
|
||||||
|
// but including LWS>
|
||||||
|
// LWS = [CRLF] 1*( SP | HT )
|
||||||
|
// CTL = <any US-ASCII control character
|
||||||
|
// (octets 0 - 31) and DEL (127)>
|
||||||
|
//
|
||||||
|
// RFC 7230 says:
|
||||||
|
// field-value = *( field-content / obs-fold )
|
||||||
|
// obj-fold = N/A to http2, and deprecated
|
||||||
|
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
|
||||||
|
// field-vchar = VCHAR / obs-text
|
||||||
|
// obs-text = %x80-FF
|
||||||
|
// VCHAR = "any visible [USASCII] character"
|
||||||
|
//
|
||||||
|
// http2 further says: "Similarly, HTTP/2 allows header field values
|
||||||
|
// that are not valid. While most of the values that can be encoded
|
||||||
|
// will not alter header field parsing, carriage return (CR, ASCII
|
||||||
|
// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
|
||||||
|
// 0x0) might be exploited by an attacker if they are translated
|
||||||
|
// verbatim. Any request or response that contains a character not
|
||||||
|
// permitted in a header field value MUST be treated as malformed
|
||||||
|
// (Section 8.1.2.6). Valid characters are defined by the
|
||||||
|
// field-content ABNF rule in Section 3.2 of [RFC7230]."
|
||||||
|
//
|
||||||
|
// This function does not (yet?) properly handle the rejection of
|
||||||
|
// strings that begin or end with SP or HTAB.
|
||||||
|
func ValidHeaderFieldValue(v string) bool {
|
||||||
|
for i := 0; i < len(v); i++ {
|
||||||
|
b := v[i]
|
||||||
|
if isCTL(b) && !isLWS(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isASCII(s string) bool {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] >= utf8.RuneSelf {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// PunycodeHostPort returns the IDNA Punycode version
|
||||||
|
// of the provided "host" or "host:port" string.
|
||||||
|
func PunycodeHostPort(v string) (string, error) {
|
||||||
|
if isASCII(v) {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
host, port, err := net.SplitHostPort(v)
|
||||||
|
if err != nil {
|
||||||
|
// The input 'v' argument was just a "host" argument,
|
||||||
|
// without a port. This error should not be returned
|
||||||
|
// to the caller.
|
||||||
|
host = v
|
||||||
|
port = ""
|
||||||
|
}
|
||||||
|
host, err = idna.ToASCII(host)
|
||||||
|
if err != nil {
|
||||||
|
// Non-UTF-8? Not representable in Punycode, in any
|
||||||
|
// case.
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if port == "" {
|
||||||
|
return host, nil
|
||||||
|
}
|
||||||
|
return net.JoinHostPort(host, port), nil
|
||||||
|
}
|
532
vendor/golang.org/x/net/trace/events.go
generated
vendored
Normal file
532
vendor/golang.org/x/net/trace/events.go
generated
vendored
Normal file
|
@ -0,0 +1,532 @@
|
||||||
|
// Copyright 2015 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 trace
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"text/tabwriter"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxEventsPerLog = 100
|
||||||
|
|
||||||
|
type bucket struct {
|
||||||
|
MaxErrAge time.Duration
|
||||||
|
String string
|
||||||
|
}
|
||||||
|
|
||||||
|
var buckets = []bucket{
|
||||||
|
{0, "total"},
|
||||||
|
{10 * time.Second, "errs<10s"},
|
||||||
|
{1 * time.Minute, "errs<1m"},
|
||||||
|
{10 * time.Minute, "errs<10m"},
|
||||||
|
{1 * time.Hour, "errs<1h"},
|
||||||
|
{10 * time.Hour, "errs<10h"},
|
||||||
|
{24000 * time.Hour, "errors"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderEvents renders the HTML page typically served at /debug/events.
|
||||||
|
// It does not do any auth checking. The request may be nil.
|
||||||
|
//
|
||||||
|
// Most users will use the Events handler.
|
||||||
|
func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) {
|
||||||
|
now := time.Now()
|
||||||
|
data := &struct {
|
||||||
|
Families []string // family names
|
||||||
|
Buckets []bucket
|
||||||
|
Counts [][]int // eventLog count per family/bucket
|
||||||
|
|
||||||
|
// Set when a bucket has been selected.
|
||||||
|
Family string
|
||||||
|
Bucket int
|
||||||
|
EventLogs eventLogs
|
||||||
|
Expanded bool
|
||||||
|
}{
|
||||||
|
Buckets: buckets,
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Families = make([]string, 0, len(families))
|
||||||
|
famMu.RLock()
|
||||||
|
for name := range families {
|
||||||
|
data.Families = append(data.Families, name)
|
||||||
|
}
|
||||||
|
famMu.RUnlock()
|
||||||
|
sort.Strings(data.Families)
|
||||||
|
|
||||||
|
// Count the number of eventLogs in each family for each error age.
|
||||||
|
data.Counts = make([][]int, len(data.Families))
|
||||||
|
for i, name := range data.Families {
|
||||||
|
// TODO(sameer): move this loop under the family lock.
|
||||||
|
f := getEventFamily(name)
|
||||||
|
data.Counts[i] = make([]int, len(data.Buckets))
|
||||||
|
for j, b := range data.Buckets {
|
||||||
|
data.Counts[i][j] = f.Count(now, b.MaxErrAge)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if req != nil {
|
||||||
|
var ok bool
|
||||||
|
data.Family, data.Bucket, ok = parseEventsArgs(req)
|
||||||
|
if !ok {
|
||||||
|
// No-op
|
||||||
|
} else {
|
||||||
|
data.EventLogs = getEventFamily(data.Family).Copy(now, buckets[data.Bucket].MaxErrAge)
|
||||||
|
}
|
||||||
|
if data.EventLogs != nil {
|
||||||
|
defer data.EventLogs.Free()
|
||||||
|
sort.Sort(data.EventLogs)
|
||||||
|
}
|
||||||
|
if exp, err := strconv.ParseBool(req.FormValue("exp")); err == nil {
|
||||||
|
data.Expanded = exp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
famMu.RLock()
|
||||||
|
defer famMu.RUnlock()
|
||||||
|
if err := eventsTmpl().Execute(w, data); err != nil {
|
||||||
|
log.Printf("net/trace: Failed executing template: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEventsArgs(req *http.Request) (fam string, b int, ok bool) {
|
||||||
|
fam, bStr := req.FormValue("fam"), req.FormValue("b")
|
||||||
|
if fam == "" || bStr == "" {
|
||||||
|
return "", 0, false
|
||||||
|
}
|
||||||
|
b, err := strconv.Atoi(bStr)
|
||||||
|
if err != nil || b < 0 || b >= len(buckets) {
|
||||||
|
return "", 0, false
|
||||||
|
}
|
||||||
|
return fam, b, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// An EventLog provides a log of events associated with a specific object.
|
||||||
|
type EventLog interface {
|
||||||
|
// Printf formats its arguments with fmt.Sprintf and adds the
|
||||||
|
// result to the event log.
|
||||||
|
Printf(format string, a ...interface{})
|
||||||
|
|
||||||
|
// Errorf is like Printf, but it marks this event as an error.
|
||||||
|
Errorf(format string, a ...interface{})
|
||||||
|
|
||||||
|
// Finish declares that this event log is complete.
|
||||||
|
// The event log should not be used after calling this method.
|
||||||
|
Finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEventLog returns a new EventLog with the specified family name
|
||||||
|
// and title.
|
||||||
|
func NewEventLog(family, title string) EventLog {
|
||||||
|
el := newEventLog()
|
||||||
|
el.ref()
|
||||||
|
el.Family, el.Title = family, title
|
||||||
|
el.Start = time.Now()
|
||||||
|
el.events = make([]logEntry, 0, maxEventsPerLog)
|
||||||
|
el.stack = make([]uintptr, 32)
|
||||||
|
n := runtime.Callers(2, el.stack)
|
||||||
|
el.stack = el.stack[:n]
|
||||||
|
|
||||||
|
getEventFamily(family).add(el)
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) Finish() {
|
||||||
|
getEventFamily(el.Family).remove(el)
|
||||||
|
el.unref() // matches ref in New
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
famMu sync.RWMutex
|
||||||
|
families = make(map[string]*eventFamily) // family name => family
|
||||||
|
)
|
||||||
|
|
||||||
|
func getEventFamily(fam string) *eventFamily {
|
||||||
|
famMu.Lock()
|
||||||
|
defer famMu.Unlock()
|
||||||
|
f := families[fam]
|
||||||
|
if f == nil {
|
||||||
|
f = &eventFamily{}
|
||||||
|
families[fam] = f
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventFamily struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
eventLogs eventLogs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *eventFamily) add(el *eventLog) {
|
||||||
|
f.mu.Lock()
|
||||||
|
f.eventLogs = append(f.eventLogs, el)
|
||||||
|
f.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *eventFamily) remove(el *eventLog) {
|
||||||
|
f.mu.Lock()
|
||||||
|
defer f.mu.Unlock()
|
||||||
|
for i, el0 := range f.eventLogs {
|
||||||
|
if el == el0 {
|
||||||
|
copy(f.eventLogs[i:], f.eventLogs[i+1:])
|
||||||
|
f.eventLogs = f.eventLogs[:len(f.eventLogs)-1]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *eventFamily) Count(now time.Time, maxErrAge time.Duration) (n int) {
|
||||||
|
f.mu.RLock()
|
||||||
|
defer f.mu.RUnlock()
|
||||||
|
for _, el := range f.eventLogs {
|
||||||
|
if el.hasRecentError(now, maxErrAge) {
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *eventFamily) Copy(now time.Time, maxErrAge time.Duration) (els eventLogs) {
|
||||||
|
f.mu.RLock()
|
||||||
|
defer f.mu.RUnlock()
|
||||||
|
els = make(eventLogs, 0, len(f.eventLogs))
|
||||||
|
for _, el := range f.eventLogs {
|
||||||
|
if el.hasRecentError(now, maxErrAge) {
|
||||||
|
el.ref()
|
||||||
|
els = append(els, el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventLogs []*eventLog
|
||||||
|
|
||||||
|
// Free calls unref on each element of the list.
|
||||||
|
func (els eventLogs) Free() {
|
||||||
|
for _, el := range els {
|
||||||
|
el.unref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eventLogs may be sorted in reverse chronological order.
|
||||||
|
func (els eventLogs) Len() int { return len(els) }
|
||||||
|
func (els eventLogs) Less(i, j int) bool { return els[i].Start.After(els[j].Start) }
|
||||||
|
func (els eventLogs) Swap(i, j int) { els[i], els[j] = els[j], els[i] }
|
||||||
|
|
||||||
|
// A logEntry is a timestamped log entry in an event log.
|
||||||
|
type logEntry struct {
|
||||||
|
When time.Time
|
||||||
|
Elapsed time.Duration // since previous event in log
|
||||||
|
NewDay bool // whether this event is on a different day to the previous event
|
||||||
|
What string
|
||||||
|
IsErr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// WhenString returns a string representation of the elapsed time of the event.
|
||||||
|
// It will include the date if midnight was crossed.
|
||||||
|
func (e logEntry) WhenString() string {
|
||||||
|
if e.NewDay {
|
||||||
|
return e.When.Format("2006/01/02 15:04:05.000000")
|
||||||
|
}
|
||||||
|
return e.When.Format("15:04:05.000000")
|
||||||
|
}
|
||||||
|
|
||||||
|
// An eventLog represents an active event log.
|
||||||
|
type eventLog struct {
|
||||||
|
// Family is the top-level grouping of event logs to which this belongs.
|
||||||
|
Family string
|
||||||
|
|
||||||
|
// Title is the title of this event log.
|
||||||
|
Title string
|
||||||
|
|
||||||
|
// Timing information.
|
||||||
|
Start time.Time
|
||||||
|
|
||||||
|
// Call stack where this event log was created.
|
||||||
|
stack []uintptr
|
||||||
|
|
||||||
|
// Append-only sequence of events.
|
||||||
|
//
|
||||||
|
// TODO(sameer): change this to a ring buffer to avoid the array copy
|
||||||
|
// when we hit maxEventsPerLog.
|
||||||
|
mu sync.RWMutex
|
||||||
|
events []logEntry
|
||||||
|
LastErrorTime time.Time
|
||||||
|
discarded int
|
||||||
|
|
||||||
|
refs int32 // how many buckets this is in
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) reset() {
|
||||||
|
// Clear all but the mutex. Mutexes may not be copied, even when unlocked.
|
||||||
|
el.Family = ""
|
||||||
|
el.Title = ""
|
||||||
|
el.Start = time.Time{}
|
||||||
|
el.stack = nil
|
||||||
|
el.events = nil
|
||||||
|
el.LastErrorTime = time.Time{}
|
||||||
|
el.discarded = 0
|
||||||
|
el.refs = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) hasRecentError(now time.Time, maxErrAge time.Duration) bool {
|
||||||
|
if maxErrAge == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
el.mu.RLock()
|
||||||
|
defer el.mu.RUnlock()
|
||||||
|
return now.Sub(el.LastErrorTime) < maxErrAge
|
||||||
|
}
|
||||||
|
|
||||||
|
// delta returns the elapsed time since the last event or the log start,
|
||||||
|
// and whether it spans midnight.
|
||||||
|
// L >= el.mu
|
||||||
|
func (el *eventLog) delta(t time.Time) (time.Duration, bool) {
|
||||||
|
if len(el.events) == 0 {
|
||||||
|
return t.Sub(el.Start), false
|
||||||
|
}
|
||||||
|
prev := el.events[len(el.events)-1].When
|
||||||
|
return t.Sub(prev), prev.Day() != t.Day()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) Printf(format string, a ...interface{}) {
|
||||||
|
el.printf(false, format, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) Errorf(format string, a ...interface{}) {
|
||||||
|
el.printf(true, format, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) printf(isErr bool, format string, a ...interface{}) {
|
||||||
|
e := logEntry{When: time.Now(), IsErr: isErr, What: fmt.Sprintf(format, a...)}
|
||||||
|
el.mu.Lock()
|
||||||
|
e.Elapsed, e.NewDay = el.delta(e.When)
|
||||||
|
if len(el.events) < maxEventsPerLog {
|
||||||
|
el.events = append(el.events, e)
|
||||||
|
} else {
|
||||||
|
// Discard the oldest event.
|
||||||
|
if el.discarded == 0 {
|
||||||
|
// el.discarded starts at two to count for the event it
|
||||||
|
// is replacing, plus the next one that we are about to
|
||||||
|
// drop.
|
||||||
|
el.discarded = 2
|
||||||
|
} else {
|
||||||
|
el.discarded++
|
||||||
|
}
|
||||||
|
// TODO(sameer): if this causes allocations on a critical path,
|
||||||
|
// change eventLog.What to be a fmt.Stringer, as in trace.go.
|
||||||
|
el.events[0].What = fmt.Sprintf("(%d events discarded)", el.discarded)
|
||||||
|
// The timestamp of the discarded meta-event should be
|
||||||
|
// the time of the last event it is representing.
|
||||||
|
el.events[0].When = el.events[1].When
|
||||||
|
copy(el.events[1:], el.events[2:])
|
||||||
|
el.events[maxEventsPerLog-1] = e
|
||||||
|
}
|
||||||
|
if e.IsErr {
|
||||||
|
el.LastErrorTime = e.When
|
||||||
|
}
|
||||||
|
el.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) ref() {
|
||||||
|
atomic.AddInt32(&el.refs, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) unref() {
|
||||||
|
if atomic.AddInt32(&el.refs, -1) == 0 {
|
||||||
|
freeEventLog(el)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) When() string {
|
||||||
|
return el.Start.Format("2006/01/02 15:04:05.000000")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) ElapsedTime() string {
|
||||||
|
elapsed := time.Since(el.Start)
|
||||||
|
return fmt.Sprintf("%.6f", elapsed.Seconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) Stack() string {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
tw := tabwriter.NewWriter(buf, 1, 8, 1, '\t', 0)
|
||||||
|
printStackRecord(tw, el.stack)
|
||||||
|
tw.Flush()
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// printStackRecord prints the function + source line information
|
||||||
|
// for a single stack trace.
|
||||||
|
// Adapted from runtime/pprof/pprof.go.
|
||||||
|
func printStackRecord(w io.Writer, stk []uintptr) {
|
||||||
|
for _, pc := range stk {
|
||||||
|
f := runtime.FuncForPC(pc)
|
||||||
|
if f == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
file, line := f.FileLine(pc)
|
||||||
|
name := f.Name()
|
||||||
|
// Hide runtime.goexit and any runtime functions at the beginning.
|
||||||
|
if strings.HasPrefix(name, "runtime.") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "# %s\t%s:%d\n", name, file, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (el *eventLog) Events() []logEntry {
|
||||||
|
el.mu.RLock()
|
||||||
|
defer el.mu.RUnlock()
|
||||||
|
return el.events
|
||||||
|
}
|
||||||
|
|
||||||
|
// freeEventLogs is a freelist of *eventLog
|
||||||
|
var freeEventLogs = make(chan *eventLog, 1000)
|
||||||
|
|
||||||
|
// newEventLog returns a event log ready to use.
|
||||||
|
func newEventLog() *eventLog {
|
||||||
|
select {
|
||||||
|
case el := <-freeEventLogs:
|
||||||
|
return el
|
||||||
|
default:
|
||||||
|
return new(eventLog)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// freeEventLog adds el to freeEventLogs if there's room.
|
||||||
|
// This is non-blocking.
|
||||||
|
func freeEventLog(el *eventLog) {
|
||||||
|
el.reset()
|
||||||
|
select {
|
||||||
|
case freeEventLogs <- el:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventsTmplCache *template.Template
|
||||||
|
var eventsTmplOnce sync.Once
|
||||||
|
|
||||||
|
func eventsTmpl() *template.Template {
|
||||||
|
eventsTmplOnce.Do(func() {
|
||||||
|
eventsTmplCache = template.Must(template.New("events").Funcs(template.FuncMap{
|
||||||
|
"elapsed": elapsed,
|
||||||
|
"trimSpace": strings.TrimSpace,
|
||||||
|
}).Parse(eventsHTML))
|
||||||
|
})
|
||||||
|
return eventsTmplCache
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventsHTML = `
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>events</title>
|
||||||
|
</head>
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
table#req-status td.family {
|
||||||
|
padding-right: 2em;
|
||||||
|
}
|
||||||
|
table#req-status td.active {
|
||||||
|
padding-right: 1em;
|
||||||
|
}
|
||||||
|
table#req-status td.empty {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
table#reqs {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
table#reqs tr.first {
|
||||||
|
{{if $.Expanded}}font-weight: bold;{{end}}
|
||||||
|
}
|
||||||
|
table#reqs td {
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
table#reqs td.when {
|
||||||
|
text-align: right;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
table#reqs td.elapsed {
|
||||||
|
padding: 0 0.5em;
|
||||||
|
text-align: right;
|
||||||
|
white-space: pre;
|
||||||
|
width: 10em;
|
||||||
|
}
|
||||||
|
address {
|
||||||
|
font-size: smaller;
|
||||||
|
margin-top: 5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>/debug/events</h1>
|
||||||
|
|
||||||
|
<table id="req-status">
|
||||||
|
{{range $i, $fam := .Families}}
|
||||||
|
<tr>
|
||||||
|
<td class="family">{{$fam}}</td>
|
||||||
|
|
||||||
|
{{range $j, $bucket := $.Buckets}}
|
||||||
|
{{$n := index $.Counts $i $j}}
|
||||||
|
<td class="{{if not $bucket.MaxErrAge}}active{{end}}{{if not $n}}empty{{end}}">
|
||||||
|
{{if $n}}<a href="?fam={{$fam}}&b={{$j}}{{if $.Expanded}}&exp=1{{end}}">{{end}}
|
||||||
|
[{{$n}} {{$bucket.String}}]
|
||||||
|
{{if $n}}</a>{{end}}
|
||||||
|
</td>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</tr>{{end}}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{{if $.EventLogs}}
|
||||||
|
<hr />
|
||||||
|
<h3>Family: {{$.Family}}</h3>
|
||||||
|
|
||||||
|
{{if $.Expanded}}<a href="?fam={{$.Family}}&b={{$.Bucket}}">{{end}}
|
||||||
|
[Summary]{{if $.Expanded}}</a>{{end}}
|
||||||
|
|
||||||
|
{{if not $.Expanded}}<a href="?fam={{$.Family}}&b={{$.Bucket}}&exp=1">{{end}}
|
||||||
|
[Expanded]{{if not $.Expanded}}</a>{{end}}
|
||||||
|
|
||||||
|
<table id="reqs">
|
||||||
|
<tr><th>When</th><th>Elapsed</th></tr>
|
||||||
|
{{range $el := $.EventLogs}}
|
||||||
|
<tr class="first">
|
||||||
|
<td class="when">{{$el.When}}</td>
|
||||||
|
<td class="elapsed">{{$el.ElapsedTime}}</td>
|
||||||
|
<td>{{$el.Title}}
|
||||||
|
</tr>
|
||||||
|
{{if $.Expanded}}
|
||||||
|
<tr>
|
||||||
|
<td class="when"></td>
|
||||||
|
<td class="elapsed"></td>
|
||||||
|
<td><pre>{{$el.Stack|trimSpace}}</pre></td>
|
||||||
|
</tr>
|
||||||
|
{{range $el.Events}}
|
||||||
|
<tr>
|
||||||
|
<td class="when">{{.WhenString}}</td>
|
||||||
|
<td class="elapsed">{{elapsed .Elapsed}}</td>
|
||||||
|
<td>.{{if .IsErr}}E{{else}}.{{end}}. {{.What}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
{{end}}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
365
vendor/golang.org/x/net/trace/histogram.go
generated
vendored
Normal file
365
vendor/golang.org/x/net/trace/histogram.go
generated
vendored
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
// Copyright 2015 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 trace
|
||||||
|
|
||||||
|
// This file implements histogramming for RPC statistics collection.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/net/internal/timeseries"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
bucketCount = 38
|
||||||
|
)
|
||||||
|
|
||||||
|
// histogram keeps counts of values in buckets that are spaced
|
||||||
|
// out in powers of 2: 0-1, 2-3, 4-7...
|
||||||
|
// histogram implements timeseries.Observable
|
||||||
|
type histogram struct {
|
||||||
|
sum int64 // running total of measurements
|
||||||
|
sumOfSquares float64 // square of running total
|
||||||
|
buckets []int64 // bucketed values for histogram
|
||||||
|
value int // holds a single value as an optimization
|
||||||
|
valueCount int64 // number of values recorded for single value
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMeasurement records a value measurement observation to the histogram.
|
||||||
|
func (h *histogram) addMeasurement(value int64) {
|
||||||
|
// TODO: assert invariant
|
||||||
|
h.sum += value
|
||||||
|
h.sumOfSquares += float64(value) * float64(value)
|
||||||
|
|
||||||
|
bucketIndex := getBucket(value)
|
||||||
|
|
||||||
|
if h.valueCount == 0 || (h.valueCount > 0 && h.value == bucketIndex) {
|
||||||
|
h.value = bucketIndex
|
||||||
|
h.valueCount++
|
||||||
|
} else {
|
||||||
|
h.allocateBuckets()
|
||||||
|
h.buckets[bucketIndex]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *histogram) allocateBuckets() {
|
||||||
|
if h.buckets == nil {
|
||||||
|
h.buckets = make([]int64, bucketCount)
|
||||||
|
h.buckets[h.value] = h.valueCount
|
||||||
|
h.value = 0
|
||||||
|
h.valueCount = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func log2(i int64) int {
|
||||||
|
n := 0
|
||||||
|
for ; i >= 0x100; i >>= 8 {
|
||||||
|
n += 8
|
||||||
|
}
|
||||||
|
for ; i > 0; i >>= 1 {
|
||||||
|
n += 1
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBucket(i int64) (index int) {
|
||||||
|
index = log2(i) - 1
|
||||||
|
if index < 0 {
|
||||||
|
index = 0
|
||||||
|
}
|
||||||
|
if index >= bucketCount {
|
||||||
|
index = bucketCount - 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total returns the number of recorded observations.
|
||||||
|
func (h *histogram) total() (total int64) {
|
||||||
|
if h.valueCount >= 0 {
|
||||||
|
total = h.valueCount
|
||||||
|
}
|
||||||
|
for _, val := range h.buckets {
|
||||||
|
total += int64(val)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Average returns the average value of recorded observations.
|
||||||
|
func (h *histogram) average() float64 {
|
||||||
|
t := h.total()
|
||||||
|
if t == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return float64(h.sum) / float64(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variance returns the variance of recorded observations.
|
||||||
|
func (h *histogram) variance() float64 {
|
||||||
|
t := float64(h.total())
|
||||||
|
if t == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
s := float64(h.sum) / t
|
||||||
|
return h.sumOfSquares/t - s*s
|
||||||
|
}
|
||||||
|
|
||||||
|
// StandardDeviation returns the standard deviation of recorded observations.
|
||||||
|
func (h *histogram) standardDeviation() float64 {
|
||||||
|
return math.Sqrt(h.variance())
|
||||||
|
}
|
||||||
|
|
||||||
|
// PercentileBoundary estimates the value that the given fraction of recorded
|
||||||
|
// observations are less than.
|
||||||
|
func (h *histogram) percentileBoundary(percentile float64) int64 {
|
||||||
|
total := h.total()
|
||||||
|
|
||||||
|
// Corner cases (make sure result is strictly less than Total())
|
||||||
|
if total == 0 {
|
||||||
|
return 0
|
||||||
|
} else if total == 1 {
|
||||||
|
return int64(h.average())
|
||||||
|
}
|
||||||
|
|
||||||
|
percentOfTotal := round(float64(total) * percentile)
|
||||||
|
var runningTotal int64
|
||||||
|
|
||||||
|
for i := range h.buckets {
|
||||||
|
value := h.buckets[i]
|
||||||
|
runningTotal += value
|
||||||
|
if runningTotal == percentOfTotal {
|
||||||
|
// We hit an exact bucket boundary. If the next bucket has data, it is a
|
||||||
|
// good estimate of the value. If the bucket is empty, we interpolate the
|
||||||
|
// midpoint between the next bucket's boundary and the next non-zero
|
||||||
|
// bucket. If the remaining buckets are all empty, then we use the
|
||||||
|
// boundary for the next bucket as the estimate.
|
||||||
|
j := uint8(i + 1)
|
||||||
|
min := bucketBoundary(j)
|
||||||
|
if runningTotal < total {
|
||||||
|
for h.buckets[j] == 0 {
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max := bucketBoundary(j)
|
||||||
|
return min + round(float64(max-min)/2)
|
||||||
|
} else if runningTotal > percentOfTotal {
|
||||||
|
// The value is in this bucket. Interpolate the value.
|
||||||
|
delta := runningTotal - percentOfTotal
|
||||||
|
percentBucket := float64(value-delta) / float64(value)
|
||||||
|
bucketMin := bucketBoundary(uint8(i))
|
||||||
|
nextBucketMin := bucketBoundary(uint8(i + 1))
|
||||||
|
bucketSize := nextBucketMin - bucketMin
|
||||||
|
return bucketMin + round(percentBucket*float64(bucketSize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bucketBoundary(bucketCount - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Median returns the estimated median of the observed values.
|
||||||
|
func (h *histogram) median() int64 {
|
||||||
|
return h.percentileBoundary(0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds other to h.
|
||||||
|
func (h *histogram) Add(other timeseries.Observable) {
|
||||||
|
o := other.(*histogram)
|
||||||
|
if o.valueCount == 0 {
|
||||||
|
// Other histogram is empty
|
||||||
|
} else if h.valueCount >= 0 && o.valueCount > 0 && h.value == o.value {
|
||||||
|
// Both have a single bucketed value, aggregate them
|
||||||
|
h.valueCount += o.valueCount
|
||||||
|
} else {
|
||||||
|
// Two different values necessitate buckets in this histogram
|
||||||
|
h.allocateBuckets()
|
||||||
|
if o.valueCount >= 0 {
|
||||||
|
h.buckets[o.value] += o.valueCount
|
||||||
|
} else {
|
||||||
|
for i := range h.buckets {
|
||||||
|
h.buckets[i] += o.buckets[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.sumOfSquares += o.sumOfSquares
|
||||||
|
h.sum += o.sum
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear resets the histogram to an empty state, removing all observed values.
|
||||||
|
func (h *histogram) Clear() {
|
||||||
|
h.buckets = nil
|
||||||
|
h.value = 0
|
||||||
|
h.valueCount = 0
|
||||||
|
h.sum = 0
|
||||||
|
h.sumOfSquares = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFrom copies from other, which must be a *histogram, into h.
|
||||||
|
func (h *histogram) CopyFrom(other timeseries.Observable) {
|
||||||
|
o := other.(*histogram)
|
||||||
|
if o.valueCount == -1 {
|
||||||
|
h.allocateBuckets()
|
||||||
|
copy(h.buckets, o.buckets)
|
||||||
|
}
|
||||||
|
h.sum = o.sum
|
||||||
|
h.sumOfSquares = o.sumOfSquares
|
||||||
|
h.value = o.value
|
||||||
|
h.valueCount = o.valueCount
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply scales the histogram by the specified ratio.
|
||||||
|
func (h *histogram) Multiply(ratio float64) {
|
||||||
|
if h.valueCount == -1 {
|
||||||
|
for i := range h.buckets {
|
||||||
|
h.buckets[i] = int64(float64(h.buckets[i]) * ratio)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.valueCount = int64(float64(h.valueCount) * ratio)
|
||||||
|
}
|
||||||
|
h.sum = int64(float64(h.sum) * ratio)
|
||||||
|
h.sumOfSquares = h.sumOfSquares * ratio
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new histogram.
|
||||||
|
func (h *histogram) New() timeseries.Observable {
|
||||||
|
r := new(histogram)
|
||||||
|
r.Clear()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *histogram) String() string {
|
||||||
|
return fmt.Sprintf("%d, %f, %d, %d, %v",
|
||||||
|
h.sum, h.sumOfSquares, h.value, h.valueCount, h.buckets)
|
||||||
|
}
|
||||||
|
|
||||||
|
// round returns the closest int64 to the argument
|
||||||
|
func round(in float64) int64 {
|
||||||
|
return int64(math.Floor(in + 0.5))
|
||||||
|
}
|
||||||
|
|
||||||
|
// bucketBoundary returns the first value in the bucket.
|
||||||
|
func bucketBoundary(bucket uint8) int64 {
|
||||||
|
if bucket == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return 1 << bucket
|
||||||
|
}
|
||||||
|
|
||||||
|
// bucketData holds data about a specific bucket for use in distTmpl.
|
||||||
|
type bucketData struct {
|
||||||
|
Lower, Upper int64
|
||||||
|
N int64
|
||||||
|
Pct, CumulativePct float64
|
||||||
|
GraphWidth int
|
||||||
|
}
|
||||||
|
|
||||||
|
// data holds data about a Distribution for use in distTmpl.
|
||||||
|
type data struct {
|
||||||
|
Buckets []*bucketData
|
||||||
|
Count, Median int64
|
||||||
|
Mean, StandardDeviation float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// maxHTMLBarWidth is the maximum width of the HTML bar for visualizing buckets.
|
||||||
|
const maxHTMLBarWidth = 350.0
|
||||||
|
|
||||||
|
// newData returns data representing h for use in distTmpl.
|
||||||
|
func (h *histogram) newData() *data {
|
||||||
|
// Force the allocation of buckets to simplify the rendering implementation
|
||||||
|
h.allocateBuckets()
|
||||||
|
// We scale the bars on the right so that the largest bar is
|
||||||
|
// maxHTMLBarWidth pixels in width.
|
||||||
|
maxBucket := int64(0)
|
||||||
|
for _, n := range h.buckets {
|
||||||
|
if n > maxBucket {
|
||||||
|
maxBucket = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total := h.total()
|
||||||
|
barsizeMult := maxHTMLBarWidth / float64(maxBucket)
|
||||||
|
var pctMult float64
|
||||||
|
if total == 0 {
|
||||||
|
pctMult = 1.0
|
||||||
|
} else {
|
||||||
|
pctMult = 100.0 / float64(total)
|
||||||
|
}
|
||||||
|
|
||||||
|
buckets := make([]*bucketData, len(h.buckets))
|
||||||
|
runningTotal := int64(0)
|
||||||
|
for i, n := range h.buckets {
|
||||||
|
if n == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
runningTotal += n
|
||||||
|
var upperBound int64
|
||||||
|
if i < bucketCount-1 {
|
||||||
|
upperBound = bucketBoundary(uint8(i + 1))
|
||||||
|
} else {
|
||||||
|
upperBound = math.MaxInt64
|
||||||
|
}
|
||||||
|
buckets[i] = &bucketData{
|
||||||
|
Lower: bucketBoundary(uint8(i)),
|
||||||
|
Upper: upperBound,
|
||||||
|
N: n,
|
||||||
|
Pct: float64(n) * pctMult,
|
||||||
|
CumulativePct: float64(runningTotal) * pctMult,
|
||||||
|
GraphWidth: int(float64(n) * barsizeMult),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &data{
|
||||||
|
Buckets: buckets,
|
||||||
|
Count: total,
|
||||||
|
Median: h.median(),
|
||||||
|
Mean: h.average(),
|
||||||
|
StandardDeviation: h.standardDeviation(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *histogram) html() template.HTML {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := distTmpl().Execute(buf, h.newData()); err != nil {
|
||||||
|
buf.Reset()
|
||||||
|
log.Printf("net/trace: couldn't execute template: %v", err)
|
||||||
|
}
|
||||||
|
return template.HTML(buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var distTmplCache *template.Template
|
||||||
|
var distTmplOnce sync.Once
|
||||||
|
|
||||||
|
func distTmpl() *template.Template {
|
||||||
|
distTmplOnce.Do(func() {
|
||||||
|
// Input: data
|
||||||
|
distTmplCache = template.Must(template.New("distTmpl").Parse(`
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:0.25em">Count: {{.Count}}</td>
|
||||||
|
<td style="padding:0.25em">Mean: {{printf "%.0f" .Mean}}</td>
|
||||||
|
<td style="padding:0.25em">StdDev: {{printf "%.0f" .StandardDeviation}}</td>
|
||||||
|
<td style="padding:0.25em">Median: {{.Median}}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<table>
|
||||||
|
{{range $b := .Buckets}}
|
||||||
|
{{if $b}}
|
||||||
|
<tr>
|
||||||
|
<td style="padding:0 0 0 0.25em">[</td>
|
||||||
|
<td style="text-align:right;padding:0 0.25em">{{.Lower}},</td>
|
||||||
|
<td style="text-align:right;padding:0 0.25em">{{.Upper}})</td>
|
||||||
|
<td style="text-align:right;padding:0 0.25em">{{.N}}</td>
|
||||||
|
<td style="text-align:right;padding:0 0.25em">{{printf "%#.3f" .Pct}}%</td>
|
||||||
|
<td style="text-align:right;padding:0 0.25em">{{printf "%#.3f" .CumulativePct}}%</td>
|
||||||
|
<td><div style="background-color: blue; height: 1em; width: {{.GraphWidth}};"></div></td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
`))
|
||||||
|
})
|
||||||
|
return distTmplCache
|
||||||
|
}
|
1082
vendor/golang.org/x/net/trace/trace.go
generated
vendored
Normal file
1082
vendor/golang.org/x/net/trace/trace.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
21
vendor/golang.org/x/net/trace/trace_go16.go
generated
vendored
Normal file
21
vendor/golang.org/x/net/trace/trace_go16.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package trace
|
||||||
|
|
||||||
|
import "golang.org/x/net/context"
|
||||||
|
|
||||||
|
// NewContext returns a copy of the parent context
|
||||||
|
// and associates it with a Trace.
|
||||||
|
func NewContext(ctx context.Context, tr Trace) context.Context {
|
||||||
|
return context.WithValue(ctx, contextKey, tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromContext returns the Trace bound to the context, if any.
|
||||||
|
func FromContext(ctx context.Context) (tr Trace, ok bool) {
|
||||||
|
tr, ok = ctx.Value(contextKey).(Trace)
|
||||||
|
return
|
||||||
|
}
|
21
vendor/golang.org/x/net/trace/trace_go17.go
generated
vendored
Normal file
21
vendor/golang.org/x/net/trace/trace_go17.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package trace
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// NewContext returns a copy of the parent context
|
||||||
|
// and associates it with a Trace.
|
||||||
|
func NewContext(ctx context.Context, tr Trace) context.Context {
|
||||||
|
return context.WithValue(ctx, contextKey, tr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromContext returns the Trace bound to the context, if any.
|
||||||
|
func FromContext(ctx context.Context) (tr Trace, ok bool) {
|
||||||
|
tr, ok = ctx.Value(contextKey).(Trace)
|
||||||
|
return
|
||||||
|
}
|
3
vendor/golang.org/x/text/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/text/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/AUTHORS.
|
3
vendor/golang.org/x/text/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/text/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/text/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/text/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009 The Go 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 Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/golang.org/x/text/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/text/PATENTS
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
340
vendor/golang.org/x/text/secure/bidirule/bidirule.go
generated
vendored
Normal file
340
vendor/golang.org/x/text/secure/bidirule/bidirule.go
generated
vendored
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
// Copyright 2016 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 bidirule implements the Bidi Rule defined by RFC 5893.
|
||||||
|
//
|
||||||
|
// This package is under development. The API may change without notice and
|
||||||
|
// without preserving backward compatibility.
|
||||||
|
package bidirule
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"golang.org/x/text/transform"
|
||||||
|
"golang.org/x/text/unicode/bidi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file contains an implementation of RFC 5893: Right-to-Left Scripts for
|
||||||
|
// Internationalized Domain Names for Applications (IDNA)
|
||||||
|
//
|
||||||
|
// A label is an individual component of a domain name. Labels are usually
|
||||||
|
// shown separated by dots; for example, the domain name "www.example.com" is
|
||||||
|
// composed of three labels: "www", "example", and "com".
|
||||||
|
//
|
||||||
|
// An RTL label is a label that contains at least one character of class R, AL,
|
||||||
|
// or AN. An LTR label is any label that is not an RTL label.
|
||||||
|
//
|
||||||
|
// A "Bidi domain name" is a domain name that contains at least one RTL label.
|
||||||
|
//
|
||||||
|
// The following guarantees can be made based on the above:
|
||||||
|
//
|
||||||
|
// o In a domain name consisting of only labels that satisfy the rule,
|
||||||
|
// the requirements of Section 3 are satisfied. Note that even LTR
|
||||||
|
// labels and pure ASCII labels have to be tested.
|
||||||
|
//
|
||||||
|
// o In a domain name consisting of only LDH labels (as defined in the
|
||||||
|
// Definitions document [RFC5890]) and labels that satisfy the rule,
|
||||||
|
// the requirements of Section 3 are satisfied as long as a label
|
||||||
|
// that starts with an ASCII digit does not come after a
|
||||||
|
// right-to-left label.
|
||||||
|
//
|
||||||
|
// No guarantee is given for other combinations.
|
||||||
|
|
||||||
|
// ErrInvalid indicates a label is invalid according to the Bidi Rule.
|
||||||
|
var ErrInvalid = errors.New("bidirule: failed Bidi Rule")
|
||||||
|
|
||||||
|
type ruleState uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ruleInitial ruleState = iota
|
||||||
|
ruleLTR
|
||||||
|
ruleLTRFinal
|
||||||
|
ruleRTL
|
||||||
|
ruleRTLFinal
|
||||||
|
ruleInvalid
|
||||||
|
)
|
||||||
|
|
||||||
|
type ruleTransition struct {
|
||||||
|
next ruleState
|
||||||
|
mask uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
var transitions = [...][2]ruleTransition{
|
||||||
|
// [2.1] The first character must be a character with Bidi property L, R, or
|
||||||
|
// AL. If it has the R or AL property, it is an RTL label; if it has the L
|
||||||
|
// property, it is an LTR label.
|
||||||
|
ruleInitial: {
|
||||||
|
{ruleLTRFinal, 1 << bidi.L},
|
||||||
|
{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL},
|
||||||
|
},
|
||||||
|
ruleRTL: {
|
||||||
|
// [2.3] In an RTL label, the end of the label must be a character with
|
||||||
|
// Bidi property R, AL, EN, or AN, followed by zero or more characters
|
||||||
|
// with Bidi property NSM.
|
||||||
|
{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL | 1<<bidi.EN | 1<<bidi.AN},
|
||||||
|
|
||||||
|
// [2.2] In an RTL label, only characters with the Bidi properties R,
|
||||||
|
// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
|
||||||
|
// We exclude the entries from [2.3]
|
||||||
|
{ruleRTL, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN | 1<<bidi.NSM},
|
||||||
|
},
|
||||||
|
ruleRTLFinal: {
|
||||||
|
// [2.3] In an RTL label, the end of the label must be a character with
|
||||||
|
// Bidi property R, AL, EN, or AN, followed by zero or more characters
|
||||||
|
// with Bidi property NSM.
|
||||||
|
{ruleRTLFinal, 1<<bidi.R | 1<<bidi.AL | 1<<bidi.EN | 1<<bidi.AN | 1<<bidi.NSM},
|
||||||
|
|
||||||
|
// [2.2] In an RTL label, only characters with the Bidi properties R,
|
||||||
|
// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
|
||||||
|
// We exclude the entries from [2.3] and NSM.
|
||||||
|
{ruleRTL, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN},
|
||||||
|
},
|
||||||
|
ruleLTR: {
|
||||||
|
// [2.6] In an LTR label, the end of the label must be a character with
|
||||||
|
// Bidi property L or EN, followed by zero or more characters with Bidi
|
||||||
|
// property NSM.
|
||||||
|
{ruleLTRFinal, 1<<bidi.L | 1<<bidi.EN},
|
||||||
|
|
||||||
|
// [2.5] In an LTR label, only characters with the Bidi properties L,
|
||||||
|
// EN, ES, CS, ET, ON, BN, or NSM are allowed.
|
||||||
|
// We exclude the entries from [2.6].
|
||||||
|
{ruleLTR, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN | 1<<bidi.NSM},
|
||||||
|
},
|
||||||
|
ruleLTRFinal: {
|
||||||
|
// [2.6] In an LTR label, the end of the label must be a character with
|
||||||
|
// Bidi property L or EN, followed by zero or more characters with Bidi
|
||||||
|
// property NSM.
|
||||||
|
{ruleLTRFinal, 1<<bidi.L | 1<<bidi.EN | 1<<bidi.NSM},
|
||||||
|
|
||||||
|
// [2.5] In an LTR label, only characters with the Bidi properties L,
|
||||||
|
// EN, ES, CS, ET, ON, BN, or NSM are allowed.
|
||||||
|
// We exclude the entries from [2.6].
|
||||||
|
{ruleLTR, 1<<bidi.ES | 1<<bidi.CS | 1<<bidi.ET | 1<<bidi.ON | 1<<bidi.BN},
|
||||||
|
},
|
||||||
|
ruleInvalid: {
|
||||||
|
{ruleInvalid, 0},
|
||||||
|
{ruleInvalid, 0},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// [2.4] In an RTL label, if an EN is present, no AN may be present, and
|
||||||
|
// vice versa.
|
||||||
|
const exclusiveRTL = uint16(1<<bidi.EN | 1<<bidi.AN)
|
||||||
|
|
||||||
|
// From RFC 5893
|
||||||
|
// An RTL label is a label that contains at least one character of type
|
||||||
|
// R, AL, or AN.
|
||||||
|
//
|
||||||
|
// An LTR label is any label that is not an RTL label.
|
||||||
|
|
||||||
|
// Direction reports the direction of the given label as defined by RFC 5893.
|
||||||
|
// The Bidi Rule does not have to be applied to labels of the category
|
||||||
|
// LeftToRight.
|
||||||
|
func Direction(b []byte) bidi.Direction {
|
||||||
|
for i := 0; i < len(b); {
|
||||||
|
e, sz := bidi.Lookup(b[i:])
|
||||||
|
if sz == 0 {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
c := e.Class()
|
||||||
|
if c == bidi.R || c == bidi.AL || c == bidi.AN {
|
||||||
|
return bidi.RightToLeft
|
||||||
|
}
|
||||||
|
i += sz
|
||||||
|
}
|
||||||
|
return bidi.LeftToRight
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectionString reports the direction of the given label as defined by RFC
|
||||||
|
// 5893. The Bidi Rule does not have to be applied to labels of the category
|
||||||
|
// LeftToRight.
|
||||||
|
func DirectionString(s string) bidi.Direction {
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
e, sz := bidi.LookupString(s[i:])
|
||||||
|
if sz == 0 {
|
||||||
|
i++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c := e.Class()
|
||||||
|
if c == bidi.R || c == bidi.AL || c == bidi.AN {
|
||||||
|
return bidi.RightToLeft
|
||||||
|
}
|
||||||
|
i += sz
|
||||||
|
}
|
||||||
|
return bidi.LeftToRight
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid reports whether b conforms to the BiDi rule.
|
||||||
|
func Valid(b []byte) bool {
|
||||||
|
var t Transformer
|
||||||
|
if n, ok := t.advance(b); !ok || n < len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return t.isFinal()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidString reports whether s conforms to the BiDi rule.
|
||||||
|
func ValidString(s string) bool {
|
||||||
|
var t Transformer
|
||||||
|
if n, ok := t.advanceString(s); !ok || n < len(s) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return t.isFinal()
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a Transformer that verifies that input adheres to the Bidi Rule.
|
||||||
|
func New() *Transformer {
|
||||||
|
return &Transformer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transformer implements transform.Transform.
|
||||||
|
type Transformer struct {
|
||||||
|
state ruleState
|
||||||
|
hasRTL bool
|
||||||
|
seen uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// A rule can only be violated for "Bidi Domain names", meaning if one of the
|
||||||
|
// following categories has been observed.
|
||||||
|
func (t *Transformer) isRTL() bool {
|
||||||
|
const isRTL = 1<<bidi.R | 1<<bidi.AL | 1<<bidi.AN
|
||||||
|
return t.seen&isRTL != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transformer) isFinal() bool {
|
||||||
|
return t.state == ruleLTRFinal || t.state == ruleRTLFinal || t.state == ruleInitial
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset implements transform.Transformer.
|
||||||
|
func (t *Transformer) Reset() { *t = Transformer{} }
|
||||||
|
|
||||||
|
// Transform implements transform.Transformer. This Transformer has state and
|
||||||
|
// needs to be reset between uses.
|
||||||
|
func (t *Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||||
|
if len(dst) < len(src) {
|
||||||
|
src = src[:len(dst)]
|
||||||
|
atEOF = false
|
||||||
|
err = transform.ErrShortDst
|
||||||
|
}
|
||||||
|
n, err1 := t.Span(src, atEOF)
|
||||||
|
copy(dst, src[:n])
|
||||||
|
if err == nil || err1 != nil && err1 != transform.ErrShortSrc {
|
||||||
|
err = err1
|
||||||
|
}
|
||||||
|
return n, n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Span returns the first n bytes of src that conform to the Bidi rule.
|
||||||
|
func (t *Transformer) Span(src []byte, atEOF bool) (n int, err error) {
|
||||||
|
if t.state == ruleInvalid && t.isRTL() {
|
||||||
|
return 0, ErrInvalid
|
||||||
|
}
|
||||||
|
n, ok := t.advance(src)
|
||||||
|
switch {
|
||||||
|
case !ok:
|
||||||
|
err = ErrInvalid
|
||||||
|
case n < len(src):
|
||||||
|
if !atEOF {
|
||||||
|
err = transform.ErrShortSrc
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err = ErrInvalid
|
||||||
|
case !t.isFinal():
|
||||||
|
err = ErrInvalid
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Precomputing the ASCII values decreases running time for the ASCII fast path
|
||||||
|
// by about 30%.
|
||||||
|
var asciiTable [128]bidi.Properties
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := range asciiTable {
|
||||||
|
p, _ := bidi.LookupRune(rune(i))
|
||||||
|
asciiTable[i] = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transformer) advance(s []byte) (n int, ok bool) {
|
||||||
|
var e bidi.Properties
|
||||||
|
var sz int
|
||||||
|
for n < len(s) {
|
||||||
|
if s[n] < utf8.RuneSelf {
|
||||||
|
e, sz = asciiTable[s[n]], 1
|
||||||
|
} else {
|
||||||
|
e, sz = bidi.Lookup(s[n:])
|
||||||
|
if sz <= 1 {
|
||||||
|
if sz == 1 {
|
||||||
|
// We always consider invalid UTF-8 to be invalid, even if
|
||||||
|
// the string has not yet been determined to be RTL.
|
||||||
|
// TODO: is this correct?
|
||||||
|
return n, false
|
||||||
|
}
|
||||||
|
return n, true // incomplete UTF-8 encoding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: using CompactClass would result in noticeable speedup.
|
||||||
|
// See unicode/bidi/prop.go:Properties.CompactClass.
|
||||||
|
c := uint16(1 << e.Class())
|
||||||
|
t.seen |= c
|
||||||
|
if t.seen&exclusiveRTL == exclusiveRTL {
|
||||||
|
t.state = ruleInvalid
|
||||||
|
return n, false
|
||||||
|
}
|
||||||
|
switch tr := transitions[t.state]; {
|
||||||
|
case tr[0].mask&c != 0:
|
||||||
|
t.state = tr[0].next
|
||||||
|
case tr[1].mask&c != 0:
|
||||||
|
t.state = tr[1].next
|
||||||
|
default:
|
||||||
|
t.state = ruleInvalid
|
||||||
|
if t.isRTL() {
|
||||||
|
return n, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n += sz
|
||||||
|
}
|
||||||
|
return n, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Transformer) advanceString(s string) (n int, ok bool) {
|
||||||
|
var e bidi.Properties
|
||||||
|
var sz int
|
||||||
|
for n < len(s) {
|
||||||
|
if s[n] < utf8.RuneSelf {
|
||||||
|
e, sz = asciiTable[s[n]], 1
|
||||||
|
} else {
|
||||||
|
e, sz = bidi.LookupString(s[n:])
|
||||||
|
if sz <= 1 {
|
||||||
|
if sz == 1 {
|
||||||
|
return n, false // invalid UTF-8
|
||||||
|
}
|
||||||
|
return n, true // incomplete UTF-8 encoding
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: using CompactClass results in noticeable speedup.
|
||||||
|
// See unicode/bidi/prop.go:Properties.CompactClass.
|
||||||
|
c := uint16(1 << e.Class())
|
||||||
|
t.seen |= c
|
||||||
|
if t.seen&exclusiveRTL == exclusiveRTL {
|
||||||
|
t.state = ruleInvalid
|
||||||
|
return n, false
|
||||||
|
}
|
||||||
|
switch tr := transitions[t.state]; {
|
||||||
|
case tr[0].mask&c != 0:
|
||||||
|
t.state = tr[0].next
|
||||||
|
case tr[1].mask&c != 0:
|
||||||
|
t.state = tr[1].next
|
||||||
|
default:
|
||||||
|
t.state = ruleInvalid
|
||||||
|
if t.isRTL() {
|
||||||
|
return n, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n += sz
|
||||||
|
}
|
||||||
|
return n, true
|
||||||
|
}
|
705
vendor/golang.org/x/text/transform/transform.go
generated
vendored
Normal file
705
vendor/golang.org/x/text/transform/transform.go
generated
vendored
Normal file
|
@ -0,0 +1,705 @@
|
||||||
|
// 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 transform provides reader and writer wrappers that transform the
|
||||||
|
// bytes passing through as well as various transformations. Example
|
||||||
|
// transformations provided by other packages include normalization and
|
||||||
|
// conversion between character sets.
|
||||||
|
package transform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrShortDst means that the destination buffer was too short to
|
||||||
|
// receive all of the transformed bytes.
|
||||||
|
ErrShortDst = errors.New("transform: short destination buffer")
|
||||||
|
|
||||||
|
// ErrShortSrc means that the source buffer has insufficient data to
|
||||||
|
// complete the transformation.
|
||||||
|
ErrShortSrc = errors.New("transform: short source buffer")
|
||||||
|
|
||||||
|
// ErrEndOfSpan means that the input and output (the transformed input)
|
||||||
|
// are not identical.
|
||||||
|
ErrEndOfSpan = errors.New("transform: input and output are not identical")
|
||||||
|
|
||||||
|
// errInconsistentByteCount means that Transform returned success (nil
|
||||||
|
// error) but also returned nSrc inconsistent with the src argument.
|
||||||
|
errInconsistentByteCount = errors.New("transform: inconsistent byte count returned")
|
||||||
|
|
||||||
|
// errShortInternal means that an internal buffer is not large enough
|
||||||
|
// to make progress and the Transform operation must be aborted.
|
||||||
|
errShortInternal = errors.New("transform: short internal buffer")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Transformer transforms bytes.
|
||||||
|
type Transformer interface {
|
||||||
|
// Transform writes to dst the transformed bytes read from src, and
|
||||||
|
// returns the number of dst bytes written and src bytes read. The
|
||||||
|
// atEOF argument tells whether src represents the last bytes of the
|
||||||
|
// input.
|
||||||
|
//
|
||||||
|
// Callers should always process the nDst bytes produced and account
|
||||||
|
// for the nSrc bytes consumed before considering the error err.
|
||||||
|
//
|
||||||
|
// A nil error means that all of the transformed bytes (whether freshly
|
||||||
|
// transformed from src or left over from previous Transform calls)
|
||||||
|
// were written to dst. A nil error can be returned regardless of
|
||||||
|
// whether atEOF is true. If err is nil then nSrc must equal len(src);
|
||||||
|
// the converse is not necessarily true.
|
||||||
|
//
|
||||||
|
// ErrShortDst means that dst was too short to receive all of the
|
||||||
|
// transformed bytes. ErrShortSrc means that src had insufficient data
|
||||||
|
// to complete the transformation. If both conditions apply, then
|
||||||
|
// either error may be returned. Other than the error conditions listed
|
||||||
|
// here, implementations are free to report other errors that arise.
|
||||||
|
Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
|
||||||
|
|
||||||
|
// Reset resets the state and allows a Transformer to be reused.
|
||||||
|
Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SpanningTransformer extends the Transformer interface with a Span method
|
||||||
|
// that determines how much of the input already conforms to the Transformer.
|
||||||
|
type SpanningTransformer interface {
|
||||||
|
Transformer
|
||||||
|
|
||||||
|
// Span returns a position in src such that transforming src[:n] results in
|
||||||
|
// identical output src[:n] for these bytes. It does not necessarily return
|
||||||
|
// the largest such n. The atEOF argument tells whether src represents the
|
||||||
|
// last bytes of the input.
|
||||||
|
//
|
||||||
|
// Callers should always account for the n bytes consumed before
|
||||||
|
// considering the error err.
|
||||||
|
//
|
||||||
|
// A nil error means that all input bytes are known to be identical to the
|
||||||
|
// output produced by the Transformer. A nil error can be be returned
|
||||||
|
// regardless of whether atEOF is true. If err is nil, then then n must
|
||||||
|
// equal len(src); the converse is not necessarily true.
|
||||||
|
//
|
||||||
|
// ErrEndOfSpan means that the Transformer output may differ from the
|
||||||
|
// input after n bytes. Note that n may be len(src), meaning that the output
|
||||||
|
// would contain additional bytes after otherwise identical output.
|
||||||
|
// ErrShortSrc means that src had insufficient data to determine whether the
|
||||||
|
// remaining bytes would change. Other than the error conditions listed
|
||||||
|
// here, implementations are free to report other errors that arise.
|
||||||
|
//
|
||||||
|
// Calling Span can modify the Transformer state as a side effect. In
|
||||||
|
// effect, it does the transformation just as calling Transform would, only
|
||||||
|
// without copying to a destination buffer and only up to a point it can
|
||||||
|
// determine the input and output bytes are the same. This is obviously more
|
||||||
|
// limited than calling Transform, but can be more efficient in terms of
|
||||||
|
// copying and allocating buffers. Calls to Span and Transform may be
|
||||||
|
// interleaved.
|
||||||
|
Span(src []byte, atEOF bool) (n int, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NopResetter can be embedded by implementations of Transformer to add a nop
|
||||||
|
// Reset method.
|
||||||
|
type NopResetter struct{}
|
||||||
|
|
||||||
|
// Reset implements the Reset method of the Transformer interface.
|
||||||
|
func (NopResetter) Reset() {}
|
||||||
|
|
||||||
|
// Reader wraps another io.Reader by transforming the bytes read.
|
||||||
|
type Reader struct {
|
||||||
|
r io.Reader
|
||||||
|
t Transformer
|
||||||
|
err error
|
||||||
|
|
||||||
|
// dst[dst0:dst1] contains bytes that have been transformed by t but
|
||||||
|
// not yet copied out via Read.
|
||||||
|
dst []byte
|
||||||
|
dst0, dst1 int
|
||||||
|
|
||||||
|
// src[src0:src1] contains bytes that have been read from r but not
|
||||||
|
// yet transformed through t.
|
||||||
|
src []byte
|
||||||
|
src0, src1 int
|
||||||
|
|
||||||
|
// transformComplete is whether the transformation is complete,
|
||||||
|
// regardless of whether or not it was successful.
|
||||||
|
transformComplete bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultBufSize = 4096
|
||||||
|
|
||||||
|
// NewReader returns a new Reader that wraps r by transforming the bytes read
|
||||||
|
// via t. It calls Reset on t.
|
||||||
|
func NewReader(r io.Reader, t Transformer) *Reader {
|
||||||
|
t.Reset()
|
||||||
|
return &Reader{
|
||||||
|
r: r,
|
||||||
|
t: t,
|
||||||
|
dst: make([]byte, defaultBufSize),
|
||||||
|
src: make([]byte, defaultBufSize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read implements the io.Reader interface.
|
||||||
|
func (r *Reader) Read(p []byte) (int, error) {
|
||||||
|
n, err := 0, error(nil)
|
||||||
|
for {
|
||||||
|
// Copy out any transformed bytes and return the final error if we are done.
|
||||||
|
if r.dst0 != r.dst1 {
|
||||||
|
n = copy(p, r.dst[r.dst0:r.dst1])
|
||||||
|
r.dst0 += n
|
||||||
|
if r.dst0 == r.dst1 && r.transformComplete {
|
||||||
|
return n, r.err
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
} else if r.transformComplete {
|
||||||
|
return 0, r.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to transform some source bytes, or to flush the transformer if we
|
||||||
|
// are out of source bytes. We do this even if r.r.Read returned an error.
|
||||||
|
// As the io.Reader documentation says, "process the n > 0 bytes returned
|
||||||
|
// before considering the error".
|
||||||
|
if r.src0 != r.src1 || r.err != nil {
|
||||||
|
r.dst0 = 0
|
||||||
|
r.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], r.err == io.EOF)
|
||||||
|
r.src0 += n
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
if r.src0 != r.src1 {
|
||||||
|
r.err = errInconsistentByteCount
|
||||||
|
}
|
||||||
|
// The Transform call was successful; we are complete if we
|
||||||
|
// cannot read more bytes into src.
|
||||||
|
r.transformComplete = r.err != nil
|
||||||
|
continue
|
||||||
|
case err == ErrShortDst && (r.dst1 != 0 || n != 0):
|
||||||
|
// Make room in dst by copying out, and try again.
|
||||||
|
continue
|
||||||
|
case err == ErrShortSrc && r.src1-r.src0 != len(r.src) && r.err == nil:
|
||||||
|
// Read more bytes into src via the code below, and try again.
|
||||||
|
default:
|
||||||
|
r.transformComplete = true
|
||||||
|
// The reader error (r.err) takes precedence over the
|
||||||
|
// transformer error (err) unless r.err is nil or io.EOF.
|
||||||
|
if r.err == nil || r.err == io.EOF {
|
||||||
|
r.err = err
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move any untransformed source bytes to the start of the buffer
|
||||||
|
// and read more bytes.
|
||||||
|
if r.src0 != 0 {
|
||||||
|
r.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1])
|
||||||
|
}
|
||||||
|
n, r.err = r.r.Read(r.src[r.src1:])
|
||||||
|
r.src1 += n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement ReadByte (and ReadRune??).
|
||||||
|
|
||||||
|
// Writer wraps another io.Writer by transforming the bytes read.
|
||||||
|
// The user needs to call Close to flush unwritten bytes that may
|
||||||
|
// be buffered.
|
||||||
|
type Writer struct {
|
||||||
|
w io.Writer
|
||||||
|
t Transformer
|
||||||
|
dst []byte
|
||||||
|
|
||||||
|
// src[:n] contains bytes that have not yet passed through t.
|
||||||
|
src []byte
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWriter returns a new Writer that wraps w by transforming the bytes written
|
||||||
|
// via t. It calls Reset on t.
|
||||||
|
func NewWriter(w io.Writer, t Transformer) *Writer {
|
||||||
|
t.Reset()
|
||||||
|
return &Writer{
|
||||||
|
w: w,
|
||||||
|
t: t,
|
||||||
|
dst: make([]byte, defaultBufSize),
|
||||||
|
src: make([]byte, defaultBufSize),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write implements the io.Writer interface. If there are not enough
|
||||||
|
// bytes available to complete a Transform, the bytes will be buffered
|
||||||
|
// for the next write. Call Close to convert the remaining bytes.
|
||||||
|
func (w *Writer) Write(data []byte) (n int, err error) {
|
||||||
|
src := data
|
||||||
|
if w.n > 0 {
|
||||||
|
// Append bytes from data to the last remainder.
|
||||||
|
// TODO: limit the amount copied on first try.
|
||||||
|
n = copy(w.src[w.n:], data)
|
||||||
|
w.n += n
|
||||||
|
src = w.src[:w.n]
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
nDst, nSrc, err := w.t.Transform(w.dst, src, false)
|
||||||
|
if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
|
||||||
|
return n, werr
|
||||||
|
}
|
||||||
|
src = src[nSrc:]
|
||||||
|
if w.n == 0 {
|
||||||
|
n += nSrc
|
||||||
|
} else if len(src) <= n {
|
||||||
|
// Enough bytes from w.src have been consumed. We make src point
|
||||||
|
// to data instead to reduce the copying.
|
||||||
|
w.n = 0
|
||||||
|
n -= len(src)
|
||||||
|
src = data[n:]
|
||||||
|
if n < len(data) && (err == nil || err == ErrShortSrc) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch err {
|
||||||
|
case ErrShortDst:
|
||||||
|
// This error is okay as long as we are making progress.
|
||||||
|
if nDst > 0 || nSrc > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case ErrShortSrc:
|
||||||
|
if len(src) < len(w.src) {
|
||||||
|
m := copy(w.src, src)
|
||||||
|
// If w.n > 0, bytes from data were already copied to w.src and n
|
||||||
|
// was already set to the number of bytes consumed.
|
||||||
|
if w.n == 0 {
|
||||||
|
n += m
|
||||||
|
}
|
||||||
|
w.n = m
|
||||||
|
err = nil
|
||||||
|
} else if nDst > 0 || nSrc > 0 {
|
||||||
|
// Not enough buffer to store the remainder. Keep processing as
|
||||||
|
// long as there is progress. Without this case, transforms that
|
||||||
|
// require a lookahead larger than the buffer may result in an
|
||||||
|
// error. This is not something one may expect to be common in
|
||||||
|
// practice, but it may occur when buffers are set to small
|
||||||
|
// sizes during testing.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
if w.n > 0 {
|
||||||
|
err = errInconsistentByteCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close implements the io.Closer interface.
|
||||||
|
func (w *Writer) Close() error {
|
||||||
|
src := w.src[:w.n]
|
||||||
|
for {
|
||||||
|
nDst, nSrc, err := w.t.Transform(w.dst, src, true)
|
||||||
|
if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
|
||||||
|
return werr
|
||||||
|
}
|
||||||
|
if err != ErrShortDst {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
src = src[nSrc:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type nop struct{ NopResetter }
|
||||||
|
|
||||||
|
func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||||
|
n := copy(dst, src)
|
||||||
|
if n < len(src) {
|
||||||
|
err = ErrShortDst
|
||||||
|
}
|
||||||
|
return n, n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nop) Span(src []byte, atEOF bool) (n int, err error) {
|
||||||
|
return len(src), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type discard struct{ NopResetter }
|
||||||
|
|
||||||
|
func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||||
|
return 0, len(src), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Discard is a Transformer for which all Transform calls succeed
|
||||||
|
// by consuming all bytes and writing nothing.
|
||||||
|
Discard Transformer = discard{}
|
||||||
|
|
||||||
|
// Nop is a SpanningTransformer that copies src to dst.
|
||||||
|
Nop SpanningTransformer = nop{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// chain is a sequence of links. A chain with N Transformers has N+1 links and
|
||||||
|
// N+1 buffers. Of those N+1 buffers, the first and last are the src and dst
|
||||||
|
// buffers given to chain.Transform and the middle N-1 buffers are intermediate
|
||||||
|
// buffers owned by the chain. The i'th link transforms bytes from the i'th
|
||||||
|
// buffer chain.link[i].b at read offset chain.link[i].p to the i+1'th buffer
|
||||||
|
// chain.link[i+1].b at write offset chain.link[i+1].n, for i in [0, N).
|
||||||
|
type chain struct {
|
||||||
|
link []link
|
||||||
|
err error
|
||||||
|
// errStart is the index at which the error occurred plus 1. Processing
|
||||||
|
// errStart at this level at the next call to Transform. As long as
|
||||||
|
// errStart > 0, chain will not consume any more source bytes.
|
||||||
|
errStart int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *chain) fatalError(errIndex int, err error) {
|
||||||
|
if i := errIndex + 1; i > c.errStart {
|
||||||
|
c.errStart = i
|
||||||
|
c.err = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type link struct {
|
||||||
|
t Transformer
|
||||||
|
// b[p:n] holds the bytes to be transformed by t.
|
||||||
|
b []byte
|
||||||
|
p int
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *link) src() []byte {
|
||||||
|
return l.b[l.p:l.n]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *link) dst() []byte {
|
||||||
|
return l.b[l.n:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chain returns a Transformer that applies t in sequence.
|
||||||
|
func Chain(t ...Transformer) Transformer {
|
||||||
|
if len(t) == 0 {
|
||||||
|
return nop{}
|
||||||
|
}
|
||||||
|
c := &chain{link: make([]link, len(t)+1)}
|
||||||
|
for i, tt := range t {
|
||||||
|
c.link[i].t = tt
|
||||||
|
}
|
||||||
|
// Allocate intermediate buffers.
|
||||||
|
b := make([][defaultBufSize]byte, len(t)-1)
|
||||||
|
for i := range b {
|
||||||
|
c.link[i+1].b = b[i][:]
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset resets the state of Chain. It calls Reset on all the Transformers.
|
||||||
|
func (c *chain) Reset() {
|
||||||
|
for i, l := range c.link {
|
||||||
|
if l.t != nil {
|
||||||
|
l.t.Reset()
|
||||||
|
}
|
||||||
|
c.link[i].p, c.link[i].n = 0, 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make chain use Span (is going to be fun to implement!)
|
||||||
|
|
||||||
|
// Transform applies the transformers of c in sequence.
|
||||||
|
func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||||
|
// Set up src and dst in the chain.
|
||||||
|
srcL := &c.link[0]
|
||||||
|
dstL := &c.link[len(c.link)-1]
|
||||||
|
srcL.b, srcL.p, srcL.n = src, 0, len(src)
|
||||||
|
dstL.b, dstL.n = dst, 0
|
||||||
|
var lastFull, needProgress bool // for detecting progress
|
||||||
|
|
||||||
|
// i is the index of the next Transformer to apply, for i in [low, high].
|
||||||
|
// low is the lowest index for which c.link[low] may still produce bytes.
|
||||||
|
// high is the highest index for which c.link[high] has a Transformer.
|
||||||
|
// The error returned by Transform determines whether to increase or
|
||||||
|
// decrease i. We try to completely fill a buffer before converting it.
|
||||||
|
for low, i, high := c.errStart, c.errStart, len(c.link)-2; low <= i && i <= high; {
|
||||||
|
in, out := &c.link[i], &c.link[i+1]
|
||||||
|
nDst, nSrc, err0 := in.t.Transform(out.dst(), in.src(), atEOF && low == i)
|
||||||
|
out.n += nDst
|
||||||
|
in.p += nSrc
|
||||||
|
if i > 0 && in.p == in.n {
|
||||||
|
in.p, in.n = 0, 0
|
||||||
|
}
|
||||||
|
needProgress, lastFull = lastFull, false
|
||||||
|
switch err0 {
|
||||||
|
case ErrShortDst:
|
||||||
|
// Process the destination buffer next. Return if we are already
|
||||||
|
// at the high index.
|
||||||
|
if i == high {
|
||||||
|
return dstL.n, srcL.p, ErrShortDst
|
||||||
|
}
|
||||||
|
if out.n != 0 {
|
||||||
|
i++
|
||||||
|
// If the Transformer at the next index is not able to process any
|
||||||
|
// source bytes there is nothing that can be done to make progress
|
||||||
|
// and the bytes will remain unprocessed. lastFull is used to
|
||||||
|
// detect this and break out of the loop with a fatal error.
|
||||||
|
lastFull = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// The destination buffer was too small, but is completely empty.
|
||||||
|
// Return a fatal error as this transformation can never complete.
|
||||||
|
c.fatalError(i, errShortInternal)
|
||||||
|
case ErrShortSrc:
|
||||||
|
if i == 0 {
|
||||||
|
// Save ErrShortSrc in err. All other errors take precedence.
|
||||||
|
err = ErrShortSrc
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Source bytes were depleted before filling up the destination buffer.
|
||||||
|
// Verify we made some progress, move the remaining bytes to the errStart
|
||||||
|
// and try to get more source bytes.
|
||||||
|
if needProgress && nSrc == 0 || in.n-in.p == len(in.b) {
|
||||||
|
// There were not enough source bytes to proceed while the source
|
||||||
|
// buffer cannot hold any more bytes. Return a fatal error as this
|
||||||
|
// transformation can never complete.
|
||||||
|
c.fatalError(i, errShortInternal)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// in.b is an internal buffer and we can make progress.
|
||||||
|
in.p, in.n = 0, copy(in.b, in.src())
|
||||||
|
fallthrough
|
||||||
|
case nil:
|
||||||
|
// if i == low, we have depleted the bytes at index i or any lower levels.
|
||||||
|
// In that case we increase low and i. In all other cases we decrease i to
|
||||||
|
// fetch more bytes before proceeding to the next index.
|
||||||
|
if i > low {
|
||||||
|
i--
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
c.fatalError(i, err0)
|
||||||
|
}
|
||||||
|
// Exhausted level low or fatal error: increase low and continue
|
||||||
|
// to process the bytes accepted so far.
|
||||||
|
i++
|
||||||
|
low = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// If c.errStart > 0, this means we found a fatal error. We will clear
|
||||||
|
// all upstream buffers. At this point, no more progress can be made
|
||||||
|
// downstream, as Transform would have bailed while handling ErrShortDst.
|
||||||
|
if c.errStart > 0 {
|
||||||
|
for i := 1; i < c.errStart; i++ {
|
||||||
|
c.link[i].p, c.link[i].n = 0, 0
|
||||||
|
}
|
||||||
|
err, c.errStart, c.err = c.err, 0, nil
|
||||||
|
}
|
||||||
|
return dstL.n, srcL.p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: use runes.Remove instead.
|
||||||
|
func RemoveFunc(f func(r rune) bool) Transformer {
|
||||||
|
return removeF(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
type removeF func(r rune) bool
|
||||||
|
|
||||||
|
func (removeF) Reset() {}
|
||||||
|
|
||||||
|
// Transform implements the Transformer interface.
|
||||||
|
func (t removeF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
||||||
|
for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] {
|
||||||
|
|
||||||
|
if r = rune(src[0]); r < utf8.RuneSelf {
|
||||||
|
sz = 1
|
||||||
|
} else {
|
||||||
|
r, sz = utf8.DecodeRune(src)
|
||||||
|
|
||||||
|
if sz == 1 {
|
||||||
|
// Invalid rune.
|
||||||
|
if !atEOF && !utf8.FullRune(src) {
|
||||||
|
err = ErrShortSrc
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// We replace illegal bytes with RuneError. Not doing so might
|
||||||
|
// otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
|
||||||
|
// The resulting byte sequence may subsequently contain runes
|
||||||
|
// for which t(r) is true that were passed unnoticed.
|
||||||
|
if !t(r) {
|
||||||
|
if nDst+3 > len(dst) {
|
||||||
|
err = ErrShortDst
|
||||||
|
break
|
||||||
|
}
|
||||||
|
nDst += copy(dst[nDst:], "\uFFFD")
|
||||||
|
}
|
||||||
|
nSrc++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !t(r) {
|
||||||
|
if nDst+sz > len(dst) {
|
||||||
|
err = ErrShortDst
|
||||||
|
break
|
||||||
|
}
|
||||||
|
nDst += copy(dst[nDst:], src[:sz])
|
||||||
|
}
|
||||||
|
nSrc += sz
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// grow returns a new []byte that is longer than b, and copies the first n bytes
|
||||||
|
// of b to the start of the new slice.
|
||||||
|
func grow(b []byte, n int) []byte {
|
||||||
|
m := len(b)
|
||||||
|
if m <= 32 {
|
||||||
|
m = 64
|
||||||
|
} else if m <= 256 {
|
||||||
|
m *= 2
|
||||||
|
} else {
|
||||||
|
m += m >> 1
|
||||||
|
}
|
||||||
|
buf := make([]byte, m)
|
||||||
|
copy(buf, b[:n])
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialBufSize = 128
|
||||||
|
|
||||||
|
// String returns a string with the result of converting s[:n] using t, where
|
||||||
|
// n <= len(s). If err == nil, n will be len(s). It calls Reset on t.
|
||||||
|
func String(t Transformer, s string) (result string, n int, err error) {
|
||||||
|
t.Reset()
|
||||||
|
if s == "" {
|
||||||
|
// Fast path for the common case for empty input. Results in about a
|
||||||
|
// 86% reduction of running time for BenchmarkStringLowerEmpty.
|
||||||
|
if _, _, err := t.Transform(nil, nil, true); err == nil {
|
||||||
|
return "", 0, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate only once. Note that both dst and src escape when passed to
|
||||||
|
// Transform.
|
||||||
|
buf := [2 * initialBufSize]byte{}
|
||||||
|
dst := buf[:initialBufSize:initialBufSize]
|
||||||
|
src := buf[initialBufSize : 2*initialBufSize]
|
||||||
|
|
||||||
|
// The input string s is transformed in multiple chunks (starting with a
|
||||||
|
// chunk size of initialBufSize). nDst and nSrc are per-chunk (or
|
||||||
|
// per-Transform-call) indexes, pDst and pSrc are overall indexes.
|
||||||
|
nDst, nSrc := 0, 0
|
||||||
|
pDst, pSrc := 0, 0
|
||||||
|
|
||||||
|
// pPrefix is the length of a common prefix: the first pPrefix bytes of the
|
||||||
|
// result will equal the first pPrefix bytes of s. It is not guaranteed to
|
||||||
|
// be the largest such value, but if pPrefix, len(result) and len(s) are
|
||||||
|
// all equal after the final transform (i.e. calling Transform with atEOF
|
||||||
|
// being true returned nil error) then we don't need to allocate a new
|
||||||
|
// result string.
|
||||||
|
pPrefix := 0
|
||||||
|
for {
|
||||||
|
// Invariant: pDst == pPrefix && pSrc == pPrefix.
|
||||||
|
|
||||||
|
n := copy(src, s[pSrc:])
|
||||||
|
nDst, nSrc, err = t.Transform(dst, src[:n], pSrc+n == len(s))
|
||||||
|
pDst += nDst
|
||||||
|
pSrc += nSrc
|
||||||
|
|
||||||
|
// TODO: let transformers implement an optional Spanner interface, akin
|
||||||
|
// to norm's QuickSpan. This would even allow us to avoid any allocation.
|
||||||
|
if !bytes.Equal(dst[:nDst], src[:nSrc]) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pPrefix = pSrc
|
||||||
|
if err == ErrShortDst {
|
||||||
|
// A buffer can only be short if a transformer modifies its input.
|
||||||
|
break
|
||||||
|
} else if err == ErrShortSrc {
|
||||||
|
if nSrc == 0 {
|
||||||
|
// No progress was made.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Equal so far and !atEOF, so continue checking.
|
||||||
|
} else if err != nil || pPrefix == len(s) {
|
||||||
|
return string(s[:pPrefix]), pPrefix, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Post-condition: pDst == pPrefix + nDst && pSrc == pPrefix + nSrc.
|
||||||
|
|
||||||
|
// We have transformed the first pSrc bytes of the input s to become pDst
|
||||||
|
// transformed bytes. Those transformed bytes are discontiguous: the first
|
||||||
|
// pPrefix of them equal s[:pPrefix] and the last nDst of them equal
|
||||||
|
// dst[:nDst]. We copy them around, into a new dst buffer if necessary, so
|
||||||
|
// that they become one contiguous slice: dst[:pDst].
|
||||||
|
if pPrefix != 0 {
|
||||||
|
newDst := dst
|
||||||
|
if pDst > len(newDst) {
|
||||||
|
newDst = make([]byte, len(s)+nDst-nSrc)
|
||||||
|
}
|
||||||
|
copy(newDst[pPrefix:pDst], dst[:nDst])
|
||||||
|
copy(newDst[:pPrefix], s[:pPrefix])
|
||||||
|
dst = newDst
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent duplicate Transform calls with atEOF being true at the end of
|
||||||
|
// the input. Also return if we have an unrecoverable error.
|
||||||
|
if (err == nil && pSrc == len(s)) ||
|
||||||
|
(err != nil && err != ErrShortDst && err != ErrShortSrc) {
|
||||||
|
return string(dst[:pDst]), pSrc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform the remaining input, growing dst and src buffers as necessary.
|
||||||
|
for {
|
||||||
|
n := copy(src, s[pSrc:])
|
||||||
|
nDst, nSrc, err := t.Transform(dst[pDst:], src[:n], pSrc+n == len(s))
|
||||||
|
pDst += nDst
|
||||||
|
pSrc += nSrc
|
||||||
|
|
||||||
|
// If we got ErrShortDst or ErrShortSrc, do not grow as long as we can
|
||||||
|
// make progress. This may avoid excessive allocations.
|
||||||
|
if err == ErrShortDst {
|
||||||
|
if nDst == 0 {
|
||||||
|
dst = grow(dst, pDst)
|
||||||
|
}
|
||||||
|
} else if err == ErrShortSrc {
|
||||||
|
if nSrc == 0 {
|
||||||
|
src = grow(src, 0)
|
||||||
|
}
|
||||||
|
} else if err != nil || pSrc == len(s) {
|
||||||
|
return string(dst[:pDst]), pSrc, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns a new byte slice with the result of converting b[:n] using t,
|
||||||
|
// where n <= len(b). If err == nil, n will be len(b). It calls Reset on t.
|
||||||
|
func Bytes(t Transformer, b []byte) (result []byte, n int, err error) {
|
||||||
|
return doAppend(t, 0, make([]byte, len(b)), b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append appends the result of converting src[:n] using t to dst, where
|
||||||
|
// n <= len(src), If err == nil, n will be len(src). It calls Reset on t.
|
||||||
|
func Append(t Transformer, dst, src []byte) (result []byte, n int, err error) {
|
||||||
|
if len(dst) == cap(dst) {
|
||||||
|
n := len(src) + len(dst) // It is okay for this to be 0.
|
||||||
|
b := make([]byte, n)
|
||||||
|
dst = b[:copy(b, dst)]
|
||||||
|
}
|
||||||
|
return doAppend(t, len(dst), dst[:cap(dst)], src)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doAppend(t Transformer, pDst int, dst, src []byte) (result []byte, n int, err error) {
|
||||||
|
t.Reset()
|
||||||
|
pSrc := 0
|
||||||
|
for {
|
||||||
|
nDst, nSrc, err := t.Transform(dst[pDst:], src[pSrc:], true)
|
||||||
|
pDst += nDst
|
||||||
|
pSrc += nSrc
|
||||||
|
if err != ErrShortDst {
|
||||||
|
return dst[:pDst], pSrc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grow the destination buffer, but do not grow as long as we can make
|
||||||
|
// progress. This may avoid excessive allocations.
|
||||||
|
if nDst == 0 {
|
||||||
|
dst = grow(dst, pDst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
198
vendor/golang.org/x/text/unicode/bidi/bidi.go
generated
vendored
Normal file
198
vendor/golang.org/x/text/unicode/bidi/bidi.go
generated
vendored
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:generate go run gen.go gen_trieval.go gen_ranges.go
|
||||||
|
|
||||||
|
// Package bidi contains functionality for bidirectional text support.
|
||||||
|
//
|
||||||
|
// See http://www.unicode.org/reports/tr9.
|
||||||
|
//
|
||||||
|
// NOTE: UNDER CONSTRUCTION. This API may change in backwards incompatible ways
|
||||||
|
// and without notice.
|
||||||
|
package bidi
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// The following functionality would not be hard to implement, but hinges on
|
||||||
|
// the definition of a Segmenter interface. For now this is up to the user.
|
||||||
|
// - Iterate over paragraphs
|
||||||
|
// - Segmenter to iterate over runs directly from a given text.
|
||||||
|
// Also:
|
||||||
|
// - Transformer for reordering?
|
||||||
|
// - Transformer (validator, really) for Bidi Rule.
|
||||||
|
|
||||||
|
// This API tries to avoid dealing with embedding levels for now. Under the hood
|
||||||
|
// these will be computed, but the question is to which extent the user should
|
||||||
|
// know they exist. We should at some point allow the user to specify an
|
||||||
|
// embedding hierarchy, though.
|
||||||
|
|
||||||
|
// A Direction indicates the overall flow of text.
|
||||||
|
type Direction int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LeftToRight indicates the text contains no right-to-left characters and
|
||||||
|
// that either there are some left-to-right characters or the option
|
||||||
|
// DefaultDirection(LeftToRight) was passed.
|
||||||
|
LeftToRight Direction = iota
|
||||||
|
|
||||||
|
// RightToLeft indicates the text contains no left-to-right characters and
|
||||||
|
// that either there are some right-to-left characters or the option
|
||||||
|
// DefaultDirection(RightToLeft) was passed.
|
||||||
|
RightToLeft
|
||||||
|
|
||||||
|
// Mixed indicates text contains both left-to-right and right-to-left
|
||||||
|
// characters.
|
||||||
|
Mixed
|
||||||
|
|
||||||
|
// Neutral means that text contains no left-to-right and right-to-left
|
||||||
|
// characters and that no default direction has been set.
|
||||||
|
Neutral
|
||||||
|
)
|
||||||
|
|
||||||
|
type options struct{}
|
||||||
|
|
||||||
|
// An Option is an option for Bidi processing.
|
||||||
|
type Option func(*options)
|
||||||
|
|
||||||
|
// ICU allows the user to define embedding levels. This may be used, for example,
|
||||||
|
// to use hierarchical structure of markup languages to define embeddings.
|
||||||
|
// The following option may be a way to expose this functionality in this API.
|
||||||
|
// // LevelFunc sets a function that associates nesting levels with the given text.
|
||||||
|
// // The levels function will be called with monotonically increasing values for p.
|
||||||
|
// func LevelFunc(levels func(p int) int) Option {
|
||||||
|
// panic("unimplemented")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// DefaultDirection sets the default direction for a Paragraph. The direction is
|
||||||
|
// overridden if the text contains directional characters.
|
||||||
|
func DefaultDirection(d Direction) Option {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Paragraph holds a single Paragraph for Bidi processing.
|
||||||
|
type Paragraph struct {
|
||||||
|
// buffers
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBytes configures p for the given paragraph text. It replaces text
|
||||||
|
// previously set by SetBytes or SetString. If b contains a paragraph separator
|
||||||
|
// it will only process the first paragraph and report the number of bytes
|
||||||
|
// consumed from b including this separator. Error may be non-nil if options are
|
||||||
|
// given.
|
||||||
|
func (p *Paragraph) SetBytes(b []byte, opts ...Option) (n int, err error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString configures p for the given paragraph text. It replaces text
|
||||||
|
// previously set by SetBytes or SetString. If b contains a paragraph separator
|
||||||
|
// it will only process the first paragraph and report the number of bytes
|
||||||
|
// consumed from b including this separator. Error may be non-nil if options are
|
||||||
|
// given.
|
||||||
|
func (p *Paragraph) SetString(s string, opts ...Option) (n int, err error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsLeftToRight reports whether the principle direction of rendering for this
|
||||||
|
// paragraphs is left-to-right. If this returns false, the principle direction
|
||||||
|
// of rendering is right-to-left.
|
||||||
|
func (p *Paragraph) IsLeftToRight() bool {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direction returns the direction of the text of this paragraph.
|
||||||
|
//
|
||||||
|
// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.
|
||||||
|
func (p *Paragraph) Direction() Direction {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunAt reports the Run at the given position of the input text.
|
||||||
|
//
|
||||||
|
// This method can be used for computing line breaks on paragraphs.
|
||||||
|
func (p *Paragraph) RunAt(pos int) Run {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Order computes the visual ordering of all the runs in a Paragraph.
|
||||||
|
func (p *Paragraph) Order() (Ordering, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Line computes the visual ordering of runs for a single line starting and
|
||||||
|
// ending at the given positions in the original text.
|
||||||
|
func (p *Paragraph) Line(start, end int) (Ordering, error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// An Ordering holds the computed visual order of runs of a Paragraph. Calling
|
||||||
|
// SetBytes or SetString on the originating Paragraph invalidates an Ordering.
|
||||||
|
// The methods of an Ordering should only be called by one goroutine at a time.
|
||||||
|
type Ordering struct{}
|
||||||
|
|
||||||
|
// Direction reports the directionality of the runs.
|
||||||
|
//
|
||||||
|
// The direction may be LeftToRight, RightToLeft, Mixed, or Neutral.
|
||||||
|
func (o *Ordering) Direction() Direction {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumRuns returns the number of runs.
|
||||||
|
func (o *Ordering) NumRuns() int {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run returns the ith run within the ordering.
|
||||||
|
func (o *Ordering) Run(i int) Run {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: perhaps with options.
|
||||||
|
// // Reorder creates a reader that reads the runes in visual order per character.
|
||||||
|
// // Modifiers remain after the runes they modify.
|
||||||
|
// func (l *Runs) Reorder() io.Reader {
|
||||||
|
// panic("unimplemented")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// A Run is a continuous sequence of characters of a single direction.
|
||||||
|
type Run struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the text of the run in its original order.
|
||||||
|
func (r *Run) String() string {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes returns the text of the run in its original order.
|
||||||
|
func (r *Run) Bytes() []byte {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: methods for
|
||||||
|
// - Display order
|
||||||
|
// - headers and footers
|
||||||
|
// - bracket replacement.
|
||||||
|
|
||||||
|
// Direction reports the direction of the run.
|
||||||
|
func (r *Run) Direction() Direction {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position of the Run within the text passed to SetBytes or SetString of the
|
||||||
|
// originating Paragraph value.
|
||||||
|
func (r *Run) Pos() (start, end int) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendReverse reverses the order of characters of in, appends them to out,
|
||||||
|
// and returns the result. Modifiers will still follow the runes they modify.
|
||||||
|
// Brackets are replaced with their counterparts.
|
||||||
|
func AppendReverse(out, in []byte) []byte {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReverseString reverses the order of characters in s and returns a new string.
|
||||||
|
// Modifiers will still follow the runes they modify. Brackets are replaced with
|
||||||
|
// their counterparts.
|
||||||
|
func ReverseString(s string) string {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
335
vendor/golang.org/x/text/unicode/bidi/bracket.go
generated
vendored
Normal file
335
vendor/golang.org/x/text/unicode/bidi/bracket.go
generated
vendored
Normal file
|
@ -0,0 +1,335 @@
|
||||||
|
// Copyright 2015 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 bidi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/list"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file contains a port of the reference implementation of the
|
||||||
|
// Bidi Parentheses Algorithm:
|
||||||
|
// http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/BidiPBAReference.java
|
||||||
|
//
|
||||||
|
// The implementation in this file covers definitions BD14-BD16 and rule N0
|
||||||
|
// of UAX#9.
|
||||||
|
//
|
||||||
|
// Some preprocessing is done for each rune before data is passed to this
|
||||||
|
// algorithm:
|
||||||
|
// - opening and closing brackets are identified
|
||||||
|
// - a bracket pair type, like '(' and ')' is assigned a unique identifier that
|
||||||
|
// is identical for the opening and closing bracket. It is left to do these
|
||||||
|
// mappings.
|
||||||
|
// - The BPA algorithm requires that bracket characters that are canonical
|
||||||
|
// equivalents of each other be able to be substituted for each other.
|
||||||
|
// It is the responsibility of the caller to do this canonicalization.
|
||||||
|
//
|
||||||
|
// In implementing BD16, this implementation departs slightly from the "logical"
|
||||||
|
// algorithm defined in UAX#9. In particular, the stack referenced there
|
||||||
|
// supports operations that go beyond a "basic" stack. An equivalent
|
||||||
|
// implementation based on a linked list is used here.
|
||||||
|
|
||||||
|
// Bidi_Paired_Bracket_Type
|
||||||
|
// BD14. An opening paired bracket is a character whose
|
||||||
|
// Bidi_Paired_Bracket_Type property value is Open.
|
||||||
|
//
|
||||||
|
// BD15. A closing paired bracket is a character whose
|
||||||
|
// Bidi_Paired_Bracket_Type property value is Close.
|
||||||
|
type bracketType byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
bpNone bracketType = iota
|
||||||
|
bpOpen
|
||||||
|
bpClose
|
||||||
|
)
|
||||||
|
|
||||||
|
// bracketPair holds a pair of index values for opening and closing bracket
|
||||||
|
// location of a bracket pair.
|
||||||
|
type bracketPair struct {
|
||||||
|
opener int
|
||||||
|
closer int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bracketPair) String() string {
|
||||||
|
return fmt.Sprintf("(%v, %v)", b.opener, b.closer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bracketPairs is a slice of bracketPairs with a sort.Interface implementation.
|
||||||
|
type bracketPairs []bracketPair
|
||||||
|
|
||||||
|
func (b bracketPairs) Len() int { return len(b) }
|
||||||
|
func (b bracketPairs) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
|
||||||
|
func (b bracketPairs) Less(i, j int) bool { return b[i].opener < b[j].opener }
|
||||||
|
|
||||||
|
// resolvePairedBrackets runs the paired bracket part of the UBA algorithm.
|
||||||
|
//
|
||||||
|
// For each rune, it takes the indexes into the original string, the class the
|
||||||
|
// bracket type (in pairTypes) and the bracket identifier (pairValues). It also
|
||||||
|
// takes the direction type for the start-of-sentence and the embedding level.
|
||||||
|
//
|
||||||
|
// The identifiers for bracket types are the rune of the canonicalized opening
|
||||||
|
// bracket for brackets (open or close) or 0 for runes that are not brackets.
|
||||||
|
func resolvePairedBrackets(s *isolatingRunSequence) {
|
||||||
|
p := bracketPairer{
|
||||||
|
sos: s.sos,
|
||||||
|
openers: list.New(),
|
||||||
|
codesIsolatedRun: s.types,
|
||||||
|
indexes: s.indexes,
|
||||||
|
}
|
||||||
|
dirEmbed := L
|
||||||
|
if s.level&1 != 0 {
|
||||||
|
dirEmbed = R
|
||||||
|
}
|
||||||
|
p.locateBrackets(s.p.pairTypes, s.p.pairValues)
|
||||||
|
p.resolveBrackets(dirEmbed, s.p.initialTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
type bracketPairer struct {
|
||||||
|
sos Class // direction corresponding to start of sequence
|
||||||
|
|
||||||
|
// The following is a restatement of BD 16 using non-algorithmic language.
|
||||||
|
//
|
||||||
|
// A bracket pair is a pair of characters consisting of an opening
|
||||||
|
// paired bracket and a closing paired bracket such that the
|
||||||
|
// Bidi_Paired_Bracket property value of the former equals the latter,
|
||||||
|
// subject to the following constraints.
|
||||||
|
// - both characters of a pair occur in the same isolating run sequence
|
||||||
|
// - the closing character of a pair follows the opening character
|
||||||
|
// - any bracket character can belong at most to one pair, the earliest possible one
|
||||||
|
// - any bracket character not part of a pair is treated like an ordinary character
|
||||||
|
// - pairs may nest properly, but their spans may not overlap otherwise
|
||||||
|
|
||||||
|
// Bracket characters with canonical decompositions are supposed to be
|
||||||
|
// treated as if they had been normalized, to allow normalized and non-
|
||||||
|
// normalized text to give the same result. In this implementation that step
|
||||||
|
// is pushed out to the caller. The caller has to ensure that the pairValue
|
||||||
|
// slices contain the rune of the opening bracket after normalization for
|
||||||
|
// any opening or closing bracket.
|
||||||
|
|
||||||
|
openers *list.List // list of positions for opening brackets
|
||||||
|
|
||||||
|
// bracket pair positions sorted by location of opening bracket
|
||||||
|
pairPositions bracketPairs
|
||||||
|
|
||||||
|
codesIsolatedRun []Class // directional bidi codes for an isolated run
|
||||||
|
indexes []int // array of index values into the original string
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchOpener reports whether characters at given positions form a matching
|
||||||
|
// bracket pair.
|
||||||
|
func (p *bracketPairer) matchOpener(pairValues []rune, opener, closer int) bool {
|
||||||
|
return pairValues[p.indexes[opener]] == pairValues[p.indexes[closer]]
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxPairingDepth = 63
|
||||||
|
|
||||||
|
// locateBrackets locates matching bracket pairs according to BD16.
|
||||||
|
//
|
||||||
|
// This implementation uses a linked list instead of a stack, because, while
|
||||||
|
// elements are added at the front (like a push) they are not generally removed
|
||||||
|
// in atomic 'pop' operations, reducing the benefit of the stack archetype.
|
||||||
|
func (p *bracketPairer) locateBrackets(pairTypes []bracketType, pairValues []rune) {
|
||||||
|
// traverse the run
|
||||||
|
// do that explicitly (not in a for-each) so we can record position
|
||||||
|
for i, index := range p.indexes {
|
||||||
|
|
||||||
|
// look at the bracket type for each character
|
||||||
|
if pairTypes[index] == bpNone || p.codesIsolatedRun[i] != ON {
|
||||||
|
// continue scanning
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch pairTypes[index] {
|
||||||
|
case bpOpen:
|
||||||
|
// check if maximum pairing depth reached
|
||||||
|
if p.openers.Len() == maxPairingDepth {
|
||||||
|
p.openers.Init()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// remember opener location, most recent first
|
||||||
|
p.openers.PushFront(i)
|
||||||
|
|
||||||
|
case bpClose:
|
||||||
|
// see if there is a match
|
||||||
|
count := 0
|
||||||
|
for elem := p.openers.Front(); elem != nil; elem = elem.Next() {
|
||||||
|
count++
|
||||||
|
opener := elem.Value.(int)
|
||||||
|
if p.matchOpener(pairValues, opener, i) {
|
||||||
|
// if the opener matches, add nested pair to the ordered list
|
||||||
|
p.pairPositions = append(p.pairPositions, bracketPair{opener, i})
|
||||||
|
// remove up to and including matched opener
|
||||||
|
for ; count > 0; count-- {
|
||||||
|
p.openers.Remove(p.openers.Front())
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Sort(p.pairPositions)
|
||||||
|
// if we get here, the closing bracket matched no openers
|
||||||
|
// and gets ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bracket pairs within an isolating run sequence are processed as units so
|
||||||
|
// that both the opening and the closing paired bracket in a pair resolve to
|
||||||
|
// the same direction.
|
||||||
|
//
|
||||||
|
// N0. Process bracket pairs in an isolating run sequence sequentially in
|
||||||
|
// the logical order of the text positions of the opening paired brackets
|
||||||
|
// using the logic given below. Within this scope, bidirectional types EN
|
||||||
|
// and AN are treated as R.
|
||||||
|
//
|
||||||
|
// Identify the bracket pairs in the current isolating run sequence
|
||||||
|
// according to BD16. For each bracket-pair element in the list of pairs of
|
||||||
|
// text positions:
|
||||||
|
//
|
||||||
|
// a Inspect the bidirectional types of the characters enclosed within the
|
||||||
|
// bracket pair.
|
||||||
|
//
|
||||||
|
// b If any strong type (either L or R) matching the embedding direction is
|
||||||
|
// found, set the type for both brackets in the pair to match the embedding
|
||||||
|
// direction.
|
||||||
|
//
|
||||||
|
// o [ e ] o -> o e e e o
|
||||||
|
//
|
||||||
|
// o [ o e ] -> o e o e e
|
||||||
|
//
|
||||||
|
// o [ NI e ] -> o e NI e e
|
||||||
|
//
|
||||||
|
// c Otherwise, if a strong type (opposite the embedding direction) is
|
||||||
|
// found, test for adjacent strong types as follows: 1 First, check
|
||||||
|
// backwards before the opening paired bracket until the first strong type
|
||||||
|
// (L, R, or sos) is found. If that first preceding strong type is opposite
|
||||||
|
// the embedding direction, then set the type for both brackets in the pair
|
||||||
|
// to that type. 2 Otherwise, set the type for both brackets in the pair to
|
||||||
|
// the embedding direction.
|
||||||
|
//
|
||||||
|
// o [ o ] e -> o o o o e
|
||||||
|
//
|
||||||
|
// o [ o NI ] o -> o o o NI o o
|
||||||
|
//
|
||||||
|
// e [ o ] o -> e e o e o
|
||||||
|
//
|
||||||
|
// e [ o ] e -> e e o e e
|
||||||
|
//
|
||||||
|
// e ( o [ o ] NI ) e -> e e o o o o NI e e
|
||||||
|
//
|
||||||
|
// d Otherwise, do not set the type for the current bracket pair. Note that
|
||||||
|
// if the enclosed text contains no strong types the paired brackets will
|
||||||
|
// both resolve to the same level when resolved individually using rules N1
|
||||||
|
// and N2.
|
||||||
|
//
|
||||||
|
// e ( NI ) o -> e ( NI ) o
|
||||||
|
|
||||||
|
// getStrongTypeN0 maps character's directional code to strong type as required
|
||||||
|
// by rule N0.
|
||||||
|
//
|
||||||
|
// TODO: have separate type for "strong" directionality.
|
||||||
|
func (p *bracketPairer) getStrongTypeN0(index int) Class {
|
||||||
|
switch p.codesIsolatedRun[index] {
|
||||||
|
// in the scope of N0, number types are treated as R
|
||||||
|
case EN, AN, AL, R:
|
||||||
|
return R
|
||||||
|
case L:
|
||||||
|
return L
|
||||||
|
default:
|
||||||
|
return ON
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// classifyPairContent reports the strong types contained inside a Bracket Pair,
|
||||||
|
// assuming the given embedding direction.
|
||||||
|
//
|
||||||
|
// It returns ON if no strong type is found. If a single strong type is found,
|
||||||
|
// it returns this this type. Otherwise it returns the embedding direction.
|
||||||
|
//
|
||||||
|
// TODO: use separate type for "strong" directionality.
|
||||||
|
func (p *bracketPairer) classifyPairContent(loc bracketPair, dirEmbed Class) Class {
|
||||||
|
dirOpposite := ON
|
||||||
|
for i := loc.opener + 1; i < loc.closer; i++ {
|
||||||
|
dir := p.getStrongTypeN0(i)
|
||||||
|
if dir == ON {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dir == dirEmbed {
|
||||||
|
return dir // type matching embedding direction found
|
||||||
|
}
|
||||||
|
dirOpposite = dir
|
||||||
|
}
|
||||||
|
// return ON if no strong type found, or class opposite to dirEmbed
|
||||||
|
return dirOpposite
|
||||||
|
}
|
||||||
|
|
||||||
|
// classBeforePair determines which strong types are present before a Bracket
|
||||||
|
// Pair. Return R or L if strong type found, otherwise ON.
|
||||||
|
func (p *bracketPairer) classBeforePair(loc bracketPair) Class {
|
||||||
|
for i := loc.opener - 1; i >= 0; i-- {
|
||||||
|
if dir := p.getStrongTypeN0(i); dir != ON {
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// no strong types found, return sos
|
||||||
|
return p.sos
|
||||||
|
}
|
||||||
|
|
||||||
|
// assignBracketType implements rule N0 for a single bracket pair.
|
||||||
|
func (p *bracketPairer) assignBracketType(loc bracketPair, dirEmbed Class, initialTypes []Class) {
|
||||||
|
// rule "N0, a", inspect contents of pair
|
||||||
|
dirPair := p.classifyPairContent(loc, dirEmbed)
|
||||||
|
|
||||||
|
// dirPair is now L, R, or N (no strong type found)
|
||||||
|
|
||||||
|
// the following logical tests are performed out of order compared to
|
||||||
|
// the statement of the rules but yield the same results
|
||||||
|
if dirPair == ON {
|
||||||
|
return // case "d" - nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
if dirPair != dirEmbed {
|
||||||
|
// case "c": strong type found, opposite - check before (c.1)
|
||||||
|
dirPair = p.classBeforePair(loc)
|
||||||
|
if dirPair == dirEmbed || dirPair == ON {
|
||||||
|
// no strong opposite type found before - use embedding (c.2)
|
||||||
|
dirPair = dirEmbed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else: case "b", strong type found matching embedding,
|
||||||
|
// no explicit action needed, as dirPair is already set to embedding
|
||||||
|
// direction
|
||||||
|
|
||||||
|
// set the bracket types to the type found
|
||||||
|
p.setBracketsToType(loc, dirPair, initialTypes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bracketPairer) setBracketsToType(loc bracketPair, dirPair Class, initialTypes []Class) {
|
||||||
|
p.codesIsolatedRun[loc.opener] = dirPair
|
||||||
|
p.codesIsolatedRun[loc.closer] = dirPair
|
||||||
|
|
||||||
|
for i := loc.opener + 1; i < loc.closer; i++ {
|
||||||
|
index := p.indexes[i]
|
||||||
|
if initialTypes[index] != NSM {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.codesIsolatedRun[i] = dirPair
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := loc.closer + 1; i < len(p.indexes); i++ {
|
||||||
|
index := p.indexes[i]
|
||||||
|
if initialTypes[index] != NSM {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.codesIsolatedRun[i] = dirPair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveBrackets implements rule N0 for a list of pairs.
|
||||||
|
func (p *bracketPairer) resolveBrackets(dirEmbed Class, initialTypes []Class) {
|
||||||
|
for _, loc := range p.pairPositions {
|
||||||
|
p.assignBracketType(loc, dirEmbed, initialTypes)
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue