Commit ead87d4f authored by Yifan Gu's avatar Yifan Gu Committed by Jonathan Boulle

Godeps: Bump rkt api, go grpc, go protobuf.

parent 0b044158
......@@ -13,7 +13,6 @@ github.com/aws/aws-sdk-go | Apache-2
github.com/beorn7/perks/quantile | MIT?
github.com/blang/semver | MITname
github.com/boltdb/bolt | MITname
github.com/bradfitz/http2 | BSDlikeRef
github.com/camlistore/go4 | Apache-2
github.com/ClusterHQ/flocker-go | UNKNOWN
github.com/codegangsta/negroni | MITname
......@@ -23,7 +22,7 @@ github.com/coreos/go-oidc | Apache-2
github.com/coreos/go-semver | Apache-2
github.com/coreos/go-systemd | Apache-2
github.com/coreos/pkg | Apache-2
github.com/coreos/rkt | Apache-2
github.com/coreos/rkt | MITname
github.com/cpuguy83/go-md2man | MITname
github.com/davecgh/go-spew | MIToldwithoutSellandNoDocumentationRequi
github.com/daviddengcn/go-colortext | BSD?
......
# This file is like Go's AUTHORS file: it lists Copyright holders.
# The list of humans who have contributd is in the CONTRIBUTORS file.
#
# To contribute to this project, because it will eventually be folded
# back in to Go itself, you need to submit a CLA:
#
# http://golang.org/doc/contribute.html#copyright
#
# Then you get added to CONTRIBUTORS and you or your company get added
# to the AUTHORS file.
Blake Mizerany <blake.mizerany@gmail.com> github=bmizerany
Daniel Morsing <daniel.morsing@gmail.com> github=DanielMorsing
Gabriel Aszalos <gabriel.aszalos@gmail.com> github=gbbr
Google, Inc.
Keith Rarick <kr@xph.us> github=kr
Matthew Keenan <tank.en.mate@gmail.com> <github@mattkeenan.net> github=mattkeenan
Matt Layher <mdlayher@gmail.com> github=mdlayher
Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> github=tatsuhiro-t
# This file is like Go's CONTRIBUTORS file: it lists humans.
# The list of copyright holders (which may be companies) are in the AUTHORS file.
#
# To contribute to this project, because it will eventually be folded
# back in to Go itself, you need to submit a CLA:
#
# http://golang.org/doc/contribute.html#copyright
#
# Then you get added to CONTRIBUTORS and you or your company get added
# to the AUTHORS file.
Blake Mizerany <blake.mizerany@gmail.com> github=bmizerany
Brad Fitzpatrick <bradfitz@golang.org> github=bradfitz
Daniel Morsing <daniel.morsing@gmail.com> github=DanielMorsing
Gabriel Aszalos <gabriel.aszalos@gmail.com> github=gbbr
Keith Rarick <kr@xph.us> github=kr
Matthew Keenan <tank.en.mate@gmail.com> <github@mattkeenan.net> github=mattkeenan
Matt Layher <mdlayher@gmail.com> github=mdlayher
Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> github=tatsuhiro-t
We only accept contributions from users who have gone through Go's
contribution process (signed a CLA).
Please acknowledge whether you have (and use the same email) if
sending a pull request.
Copyright 2014 Google & the Go AUTHORS
Go AUTHORS are:
See https://code.google.com/p/go/source/browse/AUTHORS
Licensed under the terms of Go itself:
https://code.google.com/p/go/source/browse/LICENSE
......@@ -24,6 +24,7 @@ import (
"net/url"
"reflect"
"sort"
"strconv"
"sync"
"time"
......@@ -99,6 +100,8 @@ type Config struct {
// watch start. But if server is behind some kind of proxy, the response
// header may be cached at proxy, and Client cannot rely on this behavior.
//
// Especially, wait request will ignore this timeout.
//
// One API call may send multiple requests to different etcd servers until it
// succeeds. Use context of the API to specify the overall timeout.
//
......@@ -162,6 +165,11 @@ type Client interface {
// this may differ from the initial Endpoints provided in the Config.
Endpoints() []string
// SetEndpoints sets the set of API endpoints used by Client to resolve
// HTTP requests. If the given endpoints are not valid, an error will be
// returned
SetEndpoints(eps []string) error
httpClient
}
......@@ -176,7 +184,7 @@ func New(cfg Config) (Client, error) {
password: cfg.Password,
}
}
if err := c.reset(cfg.Endpoints); err != nil {
if err := c.SetEndpoints(cfg.Endpoints); err != nil {
return nil, err
}
return c, nil
......@@ -219,7 +227,7 @@ type httpClusterClient struct {
rand *rand.Rand
}
func (c *httpClusterClient) reset(eps []string) error {
func (c *httpClusterClient) SetEndpoints(eps []string) error {
if len(eps) == 0 {
return ErrNoEndpoints
}
......@@ -341,7 +349,7 @@ func (c *httpClusterClient) Sync(ctx context.Context) error {
return nil
}
return c.reset(eps)
return c.SetEndpoints(eps)
}
func (c *httpClusterClient) AutoSync(ctx context.Context, interval time.Duration) error {
......@@ -378,9 +386,21 @@ func (c *simpleHTTPClient) Do(ctx context.Context, act httpAction) (*http.Respon
return nil, nil, err
}
isWait := false
if req != nil && req.URL != nil {
ws := req.URL.Query().Get("wait")
if len(ws) != 0 {
var err error
isWait, err = strconv.ParseBool(ws)
if err != nil {
return nil, nil, fmt.Errorf("wrong wait value %s (%v for %+v)", ws, err, req)
}
}
}
var hctx context.Context
var hcancel context.CancelFunc
if c.headerTimeout > 0 {
if !isWait && c.headerTimeout > 0 {
hctx, hcancel = context.WithTimeout(ctx, c.headerTimeout)
} else {
hctx, hcancel = context.WithCancel(ctx)
......
......@@ -95,8 +95,7 @@ type store struct {
timeout time.Duration
ensuredOnce bool
mu sync.Mutex // protect enabled
enabled *bool
mu sync.Mutex
}
type User struct {
......@@ -409,8 +408,6 @@ func (s *store) EnableAuth() error {
}
err = s.enableAuth()
if err == nil {
b := true
s.enabled = &b
plog.Noticef("auth: enabled auth")
} else {
plog.Errorf("error enabling auth (%v)", err)
......@@ -428,8 +425,6 @@ func (s *store) DisableAuth() error {
err := s.disableAuth()
if err == nil {
b := false
s.enabled = &b
plog.Noticef("auth: disabled auth")
} else {
plog.Errorf("error disabling auth (%v)", err)
......
......@@ -85,15 +85,10 @@ func (s *store) detectAuth() bool {
if s.server == nil {
return false
}
if s.enabled != nil {
return *s.enabled
}
value, err := s.requestResource("/enabled", false)
if err != nil {
if e, ok := err.(*etcderr.Error); ok {
if e.ErrorCode == etcderr.EcodeKeyNotFound {
b := false
s.enabled = &b
return false
}
}
......@@ -107,7 +102,6 @@ func (s *store) detectAuth() bool {
plog.Errorf("internal bookkeeping value for enabled isn't valid JSON (%v)", err)
return false
}
s.enabled = &u
return u
}
......
......@@ -4,15 +4,20 @@
package etcdserverpb
import proto "github.com/gogo/protobuf/proto"
import (
"fmt"
// discarding unused import gogoproto "github.com/coreos/etcd/Godeps/_workspace/src/gogoproto"
proto "github.com/gogo/protobuf/proto"
)
import math "math"
import io "io"
import fmt "fmt"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// An InternalRaftRequest is the union of all requests which can be
// sent via raft.
......@@ -28,6 +33,9 @@ func (m *InternalRaftRequest) Reset() { *m = InternalRaftRequest{} }
func (m *InternalRaftRequest) String() string { return proto.CompactTextString(m) }
func (*InternalRaftRequest) ProtoMessage() {}
func init() {
proto.RegisterType((*InternalRaftRequest)(nil), "etcdserverpb.InternalRaftRequest")
}
func (m *InternalRaftRequest) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
......@@ -162,48 +170,16 @@ func sovRaftInternal(x uint64) (n int) {
func sozRaftInternal(x uint64) (n int) {
return sovRaftInternal(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (this *InternalRaftRequest) GetValue() interface{} {
if this.V2 != nil {
return this.V2
}
if this.Range != nil {
return this.Range
}
if this.Put != nil {
return this.Put
}
if this.DeleteRange != nil {
return this.DeleteRange
}
if this.Txn != nil {
return this.Txn
}
return nil
}
func (this *InternalRaftRequest) SetValue(value interface{}) bool {
switch vt := value.(type) {
case *Request:
this.V2 = vt
case *RangeRequest:
this.Range = vt
case *PutRequest:
this.Put = vt
case *DeleteRangeRequest:
this.DeleteRange = vt
case *TxnRequest:
this.Txn = vt
default:
return false
}
return true
}
func (m *InternalRaftRequest) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -216,6 +192,12 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: InternalRaftRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: InternalRaftRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
......@@ -223,6 +205,9 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -253,6 +238,9 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -283,6 +271,9 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -313,6 +304,9 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -343,6 +337,9 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -368,15 +365,7 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
iNdEx = postIndex
default:
var sizeOfWire int
for {
sizeOfWire++
wire >>= 7
if wire == 0 {
break
}
}
iNdEx -= sizeOfWire
iNdEx = preIndex
skippy, err := skipRaftInternal(data[iNdEx:])
if err != nil {
return err
......@@ -391,6 +380,9 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipRaftInternal(data []byte) (n int, err error) {
......@@ -399,6 +391,9 @@ func skipRaftInternal(data []byte) (n int, err error) {
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -412,7 +407,10 @@ func skipRaftInternal(data []byte) (n int, err error) {
wireType := int(wire & 0x7)
switch wireType {
case 0:
for {
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -428,6 +426,9 @@ func skipRaftInternal(data []byte) (n int, err error) {
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -448,6 +449,9 @@ func skipRaftInternal(data []byte) (n int, err error) {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -483,4 +487,5 @@ func skipRaftInternal(data []byte) (n int, err error) {
var (
ErrInvalidLengthRaftInternal = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowRaftInternal = fmt.Errorf("proto: integer overflow")
)
......@@ -13,12 +13,9 @@ option (gogoproto.goproto_getters_all) = false;
// An InternalRaftRequest is the union of all requests which can be
// sent via raft.
message InternalRaftRequest {
option (gogoproto.onlyone) = true;
oneof value {
Request v2 = 1;
RangeRequest range = 2;
PutRequest put = 3;
DeleteRangeRequest delete_range = 4;
TxnRequest txn = 5;
}
}
......@@ -174,12 +174,17 @@ type EtcdServer struct {
// configuration is considered static for the lifetime of the EtcdServer.
func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
st := store.New(StoreClusterPrefix, StoreKeysPrefix)
var w *wal.WAL
var n raft.Node
var s *raft.MemoryStorage
var id types.ID
var cl *cluster
if terr := fileutil.TouchDirAll(cfg.DataDir); terr != nil {
return nil, fmt.Errorf("cannot access data directory: %v", terr)
}
// Run the migrations.
dataVer, err := version.DetectDataDir(cfg.DataDir)
if err != nil {
......@@ -189,11 +194,6 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
return nil, err
}
err = os.MkdirAll(cfg.MemberDir(), privateDirMode)
if err != nil && err != os.ErrExist {
return nil, err
}
haveWAL := wal.Exist(cfg.WALDir())
ss := snap.New(cfg.SnapDir())
......@@ -255,10 +255,6 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
cfg.PrintWithInitial()
id, n, s, w = startNode(cfg, cl, cl.MemberIDs())
case haveWAL:
if err := fileutil.IsDirWriteable(cfg.DataDir); err != nil {
return nil, fmt.Errorf("cannot write to data directory: %v", err)
}
if err := fileutil.IsDirWriteable(cfg.MemberDir()); err != nil {
return nil, fmt.Errorf("cannot write to member directory: %v", err)
}
......@@ -295,6 +291,10 @@ func NewServer(cfg *ServerConfig) (*EtcdServer, error) {
return nil, fmt.Errorf("unsupported bootstrap config")
}
if terr := fileutil.TouchDirAll(cfg.MemberDir()); terr != nil {
return nil, fmt.Errorf("cannot access member directory: %v", terr)
}
sstats := &stats.ServerStats{
Name: cfg.Name,
ID: id.String(),
......
......@@ -19,6 +19,7 @@ import (
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
dstorage "github.com/coreos/etcd/storage"
"github.com/coreos/etcd/storage/storagepb"
"github.com/gogo/protobuf/proto"
"golang.org/x/net/context"
)
......@@ -106,17 +107,24 @@ func doTxn(kv dstorage.KV, rt *pb.TxnRequest) *pb.TxnResponse {
}
func doUnion(kv dstorage.KV, union *pb.RequestUnion) *pb.ResponseUnion {
switch {
case union.RequestRange != nil:
return &pb.ResponseUnion{ResponseRange: doRange(kv, union.RequestRange)}
case union.RequestPut != nil:
return &pb.ResponseUnion{ResponsePut: doPut(kv, union.RequestPut)}
case union.RequestDeleteRange != nil:
return &pb.ResponseUnion{ResponseDeleteRange: doDeleteRange(kv, union.RequestDeleteRange)}
switch tv := union.Request.(type) {
case *pb.RequestUnion_RequestRange:
if tv.RequestRange != nil {
return &pb.ResponseUnion{Response: &pb.ResponseUnion_ResponseRange{ResponseRange: doRange(kv, tv.RequestRange)}}
}
case *pb.RequestUnion_RequestPut:
if tv.RequestPut != nil {
return &pb.ResponseUnion{Response: &pb.ResponseUnion_ResponsePut{ResponsePut: doPut(kv, tv.RequestPut)}}
}
case *pb.RequestUnion_RequestDeleteRange:
if tv.RequestDeleteRange != nil {
return &pb.ResponseUnion{Response: &pb.ResponseUnion_ResponseDeleteRange{ResponseDeleteRange: doDeleteRange(kv, tv.RequestDeleteRange)}}
}
default:
// empty union
return nil
}
return nil
}
func doCompare(kv dstorage.KV, c *pb.Compare) (int64, bool) {
......@@ -124,20 +132,35 @@ func doCompare(kv dstorage.KV, c *pb.Compare) (int64, bool) {
if err != nil {
return rev, false
}
ckv := ckvs[0]
var ckv storagepb.KeyValue
if len(ckvs) != 0 {
ckv = ckvs[0]
}
// -1 is less, 0 is equal, 1 is greater
var result int
switch c.Target {
case pb.Compare_VALUE:
result = bytes.Compare(ckv.Value, c.Value)
tv, _ := c.TargetUnion.(*pb.Compare_Value)
if tv != nil {
result = bytes.Compare(ckv.Value, tv.Value)
}
case pb.Compare_CREATE:
result = compareInt64(ckv.CreateRevision, c.CreateRevision)
tv, _ := c.TargetUnion.(*pb.Compare_CreateRevision)
if tv != nil {
result = compareInt64(ckv.CreateRevision, tv.CreateRevision)
}
case pb.Compare_MOD:
result = compareInt64(ckv.ModRevision, c.ModRevision)
tv, _ := c.TargetUnion.(*pb.Compare_ModRevision)
if tv != nil {
result = compareInt64(ckv.ModRevision, tv.ModRevision)
}
case pb.Compare_VERSION:
result = compareInt64(ckv.Version, c.Version)
tv, _ := c.TargetUnion.(*pb.Compare_Version)
if tv != nil {
result = compareInt64(ckv.Version, tv.Version)
}
}
switch c.Result {
......
......@@ -25,6 +25,8 @@ import (
const (
privateFileMode = 0600
// owner can make/remove files inside the directory
privateDirMode = 0700
)
var (
......@@ -55,3 +57,13 @@ func ReadDir(dirpath string) ([]string, error) {
sort.Strings(names)
return names, nil
}
// TouchDirAll is simliar to os.MkdirAll. It creates directories with 0700 permission if any directory
// does not exists. TouchDirAll also ensures the given directory is writable.
func TouchDirAll(dir string) error {
err := os.MkdirAll(dir, privateDirMode)
if err != nil && err != os.ErrExist {
return err
}
return IsDirWriteable(dir)
}
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ioutil
import (
"io"
"os"
)
// WriteAndSyncFile behaviors just like ioutil.WriteFile in standard library
// but calls Sync before closing the file. WriteAndSyncFile guarantees the data
// is synced if there is no error returned.
func WriteAndSyncFile(filename string, data []byte, perm os.FileMode) error {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
return err
}
n, err := f.Write(data)
if err == nil && n < len(data) {
err = io.ErrShortWrite
}
if err == nil {
err = f.Sync()
}
if err1 := f.Close(); err == nil {
err = err1
}
return err
}
......@@ -21,17 +21,19 @@ import (
"time"
)
type keepAliveConn interface {
SetKeepAlive(bool) error
SetKeepAlivePeriod(d time.Duration) error
}
// NewKeepAliveListener returns a listener that listens on the given address.
// Be careful when wrap around KeepAliveListener with another Listener if TLSInfo is not nil.
// Some pkgs (like go/http) might expect Listener to return TLSConn type to start TLS handshake.
// http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
func NewKeepAliveListener(addr string, scheme string, info TLSInfo) (net.Listener, error) {
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
func NewKeepAliveListener(l net.Listener, scheme string, info TLSInfo) (net.Listener, error) {
if scheme == "https" {
if info.Empty() {
return nil, fmt.Errorf("cannot listen on TLS for %s: KeyFile and CertFile are not presented", scheme+"://"+addr)
return nil, fmt.Errorf("cannot listen on TLS for given listener: KeyFile and CertFile are not presented")
}
cfg, err := info.ServerConfig()
if err != nil {
......@@ -53,13 +55,13 @@ func (kln *keepaliveListener) Accept() (net.Conn, error) {
if err != nil {
return nil, err
}
tcpc := c.(*net.TCPConn)
kac := c.(keepAliveConn)
// detection time: tcp_keepalive_time + tcp_keepalive_probes + tcp_keepalive_intvl
// default on linux: 30 + 8 * 30
// default on osx: 30 + 8 * 75
tcpc.SetKeepAlive(true)
tcpc.SetKeepAlivePeriod(30 * time.Second)
return tcpc, nil
kac.SetKeepAlive(true)
kac.SetKeepAlivePeriod(30 * time.Second)
return c, nil
}
// A tlsKeepaliveListener implements a network listener (net.Listener) for TLS connections.
......@@ -75,12 +77,12 @@ func (l *tlsKeepaliveListener) Accept() (c net.Conn, err error) {
if err != nil {
return
}
tcpc := c.(*net.TCPConn)
kac := c.(keepAliveConn)
// detection time: tcp_keepalive_time + tcp_keepalive_probes + tcp_keepalive_intvl
// default on linux: 30 + 8 * 30
// default on osx: 30 + 8 * 75
tcpc.SetKeepAlive(true)
tcpc.SetKeepAlivePeriod(30 * time.Second)
kac.SetKeepAlive(true)
kac.SetKeepAlivePeriod(30 * time.Second)
c = tls.Server(c, l.config)
return
}
......
// 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 netutil provides network utility functions, complementing the more
// common ones in the net package.
package transport
import (
"errors"
"net"
"sync"
"time"
)
var (
ErrNotTCP = errors.New("only tcp connections have keepalive")
)
// LimitListener returns a Listener that accepts at most n simultaneous
// connections from the provided Listener.
func LimitListener(l net.Listener, n int) net.Listener {
return &limitListener{l, make(chan struct{}, n)}
}
type limitListener struct {
net.Listener
sem chan struct{}
}
func (l *limitListener) acquire() { l.sem <- struct{}{} }
func (l *limitListener) release() { <-l.sem }
func (l *limitListener) Accept() (net.Conn, error) {
l.acquire()
c, err := l.Listener.Accept()
if err != nil {
l.release()
return nil, err
}
return &limitListenerConn{Conn: c, release: l.release}, nil
}
type limitListenerConn struct {
net.Conn
releaseOnce sync.Once
release func()
}
func (l *limitListenerConn) Close() error {
err := l.Conn.Close()
l.releaseOnce.Do(l.release)
return err
}
func (l *limitListenerConn) SetKeepAlive(doKeepAlive bool) error {
tcpc, ok := l.Conn.(*net.TCPConn)
if !ok {
return ErrNotTCP
}
return tcpc.SetKeepAlive(doKeepAlive)
}
func (l *limitListenerConn) SetKeepAlivePeriod(d time.Duration) error {
tcpc, ok := l.Conn.(*net.TCPConn)
if !ok {
return ErrNotTCP
}
return tcpc.SetKeepAlivePeriod(d)
}
......@@ -13,16 +13,19 @@
*/
package snappb
import proto "github.com/gogo/protobuf/proto"
import math "math"
import (
"fmt"
proto "github.com/gogo/protobuf/proto"
)
// discarding unused import gogoproto "github.com/coreos/etcd/Godeps/_workspace/src/gogoproto"
import math "math"
import io "io"
import fmt "fmt"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type Snapshot struct {
......@@ -35,6 +38,9 @@ func (m *Snapshot) Reset() { *m = Snapshot{} }
func (m *Snapshot) String() string { return proto.CompactTextString(m) }
func (*Snapshot) ProtoMessage() {}
func init() {
proto.RegisterType((*Snapshot)(nil), "snappb.snapshot")
}
func (m *Snapshot) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
......@@ -123,8 +129,12 @@ func (m *Snapshot) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSnap
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -137,6 +147,12 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: snapshot: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: snapshot: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
......@@ -144,6 +160,9 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
m.Crc = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSnap
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -160,6 +179,9 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowSnap
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -177,18 +199,13 @@ func (m *Snapshot) Unmarshal(data []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Data = append([]byte{}, data[iNdEx:postIndex]...)
m.Data = append(m.Data[:0], data[iNdEx:postIndex]...)
if m.Data == nil {
m.Data = []byte{}
}
iNdEx = postIndex
default:
var sizeOfWire int
for {
sizeOfWire++
wire >>= 7
if wire == 0 {
break
}
}
iNdEx -= sizeOfWire
iNdEx = preIndex
skippy, err := skipSnap(data[iNdEx:])
if err != nil {
return err
......@@ -204,6 +221,9 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipSnap(data []byte) (n int, err error) {
......@@ -212,6 +232,9 @@ func skipSnap(data []byte) (n int, err error) {
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowSnap
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -225,7 +248,10 @@ func skipSnap(data []byte) (n int, err error) {
wireType := int(wire & 0x7)
switch wireType {
case 0:
for {
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowSnap
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -241,6 +267,9 @@ func skipSnap(data []byte) (n int, err error) {
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowSnap
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -261,6 +290,9 @@ func skipSnap(data []byte) (n int, err error) {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowSnap
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -296,4 +328,5 @@ func skipSnap(data []byte) (n int, err error) {
var (
ErrInvalidLengthSnap = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowSnap = fmt.Errorf("proto: integer overflow")
)
......@@ -14,15 +14,20 @@
*/
package storagepb
import proto "github.com/gogo/protobuf/proto"
import (
"fmt"
// discarding unused import gogoproto "github.com/coreos/etcd/Godeps/_workspace/src/gogoproto"
proto "github.com/gogo/protobuf/proto"
)
import math "math"
import io "io"
import fmt "fmt"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type Event_EventType int32
......@@ -76,6 +81,8 @@ func (m *Event) String() string { return proto.CompactTextString(m) }
func (*Event) ProtoMessage() {}
func init() {
proto.RegisterType((*KeyValue)(nil), "storagepb.KeyValue")
proto.RegisterType((*Event)(nil), "storagepb.Event")
proto.RegisterEnum("storagepb.Event_EventType", Event_EventType_name, Event_EventType_value)
}
func (m *KeyValue) Marshal() (data []byte, err error) {
......@@ -244,8 +251,12 @@ func (m *KeyValue) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -258,6 +269,12 @@ func (m *KeyValue) Unmarshal(data []byte) error {
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: KeyValue: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: KeyValue: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
......@@ -265,6 +282,9 @@ func (m *KeyValue) Unmarshal(data []byte) error {
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -282,7 +302,10 @@ func (m *KeyValue) Unmarshal(data []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Key = append([]byte{}, data[iNdEx:postIndex]...)
m.Key = append(m.Key[:0], data[iNdEx:postIndex]...)
if m.Key == nil {
m.Key = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 0 {
......@@ -290,6 +313,9 @@ func (m *KeyValue) Unmarshal(data []byte) error {
}
m.CreateRevision = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -306,6 +332,9 @@ func (m *KeyValue) Unmarshal(data []byte) error {
}
m.ModRevision = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -322,6 +351,9 @@ func (m *KeyValue) Unmarshal(data []byte) error {
}
m.Version = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -338,6 +370,9 @@ func (m *KeyValue) Unmarshal(data []byte) error {
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -355,18 +390,13 @@ func (m *KeyValue) Unmarshal(data []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Value = append([]byte{}, data[iNdEx:postIndex]...)
m.Value = append(m.Value[:0], data[iNdEx:postIndex]...)
if m.Value == nil {
m.Value = []byte{}
}
iNdEx = postIndex
default:
var sizeOfWire int
for {
sizeOfWire++
wire >>= 7
if wire == 0 {
break
}
}
iNdEx -= sizeOfWire
iNdEx = preIndex
skippy, err := skipKv(data[iNdEx:])
if err != nil {
return err
......@@ -381,14 +411,21 @@ func (m *KeyValue) Unmarshal(data []byte) error {
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Event) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -401,6 +438,12 @@ func (m *Event) Unmarshal(data []byte) error {
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Event: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Event: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
......@@ -408,6 +451,9 @@ func (m *Event) Unmarshal(data []byte) error {
}
m.Type = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -424,6 +470,9 @@ func (m *Event) Unmarshal(data []byte) error {
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowKv
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -449,15 +498,7 @@ func (m *Event) Unmarshal(data []byte) error {
}
iNdEx = postIndex
default:
var sizeOfWire int
for {
sizeOfWire++
wire >>= 7
if wire == 0 {
break
}
}
iNdEx -= sizeOfWire
iNdEx = preIndex
skippy, err := skipKv(data[iNdEx:])
if err != nil {
return err
......@@ -472,6 +513,9 @@ func (m *Event) Unmarshal(data []byte) error {
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipKv(data []byte) (n int, err error) {
......@@ -480,6 +524,9 @@ func skipKv(data []byte) (n int, err error) {
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowKv
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -493,7 +540,10 @@ func skipKv(data []byte) (n int, err error) {
wireType := int(wire & 0x7)
switch wireType {
case 0:
for {
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowKv
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -509,6 +559,9 @@ func skipKv(data []byte) (n int, err error) {
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowKv
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -529,6 +582,9 @@ func skipKv(data []byte) (n int, err error) {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowKv
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -564,4 +620,5 @@ func skipKv(data []byte) (n int, err error) {
var (
ErrInvalidLengthKv = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowKv = fmt.Errorf("proto: integer overflow")
)
......@@ -27,7 +27,7 @@ import (
var (
// MinClusterVersion is the min cluster version this etcd binary is compatible with.
MinClusterVersion = "2.1.0"
Version = "2.2.2+git"
Version = "2.2.5"
// Git SHA Value will be set during build
GitSHA = "Not provided (use ./build instead of go build)"
......
......@@ -14,16 +14,19 @@
*/
package walpb
import proto "github.com/gogo/protobuf/proto"
import math "math"
import (
"fmt"
// discarding unused import gogoproto "github.com/coreos/etcd/Godeps/_workspace/src/gogoproto"
proto "github.com/gogo/protobuf/proto"
)
import math "math"
import io "io"
import fmt "fmt"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type Record struct {
......@@ -47,6 +50,10 @@ func (m *Snapshot) Reset() { *m = Snapshot{} }
func (m *Snapshot) String() string { return proto.CompactTextString(m) }
func (*Snapshot) ProtoMessage() {}
func init() {
proto.RegisterType((*Record)(nil), "walpb.Record")
proto.RegisterType((*Snapshot)(nil), "walpb.Snapshot")
}
func (m *Record) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
......@@ -177,8 +184,12 @@ func (m *Record) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -191,6 +202,12 @@ func (m *Record) Unmarshal(data []byte) error {
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Record: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Record: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
......@@ -198,6 +215,9 @@ func (m *Record) Unmarshal(data []byte) error {
}
m.Type = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -214,6 +234,9 @@ func (m *Record) Unmarshal(data []byte) error {
}
m.Crc = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -230,6 +253,9 @@ func (m *Record) Unmarshal(data []byte) error {
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -247,18 +273,13 @@ func (m *Record) Unmarshal(data []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Data = append([]byte{}, data[iNdEx:postIndex]...)
m.Data = append(m.Data[:0], data[iNdEx:postIndex]...)
if m.Data == nil {
m.Data = []byte{}
}
iNdEx = postIndex
default:
var sizeOfWire int
for {
sizeOfWire++
wire >>= 7
if wire == 0 {
break
}
}
iNdEx -= sizeOfWire
iNdEx = preIndex
skippy, err := skipRecord(data[iNdEx:])
if err != nil {
return err
......@@ -274,14 +295,21 @@ func (m *Record) Unmarshal(data []byte) error {
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Snapshot) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -294,6 +322,12 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Snapshot: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Snapshot: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
......@@ -301,6 +335,9 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
m.Index = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -317,6 +354,9 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
m.Term = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRecord
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
......@@ -328,15 +368,7 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
}
default:
var sizeOfWire int
for {
sizeOfWire++
wire >>= 7
if wire == 0 {
break
}
}
iNdEx -= sizeOfWire
iNdEx = preIndex
skippy, err := skipRecord(data[iNdEx:])
if err != nil {
return err
......@@ -352,6 +384,9 @@ func (m *Snapshot) Unmarshal(data []byte) error {
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipRecord(data []byte) (n int, err error) {
......@@ -360,6 +395,9 @@ func skipRecord(data []byte) (n int, err error) {
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRecord
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -373,7 +411,10 @@ func skipRecord(data []byte) (n int, err error) {
wireType := int(wire & 0x7)
switch wireType {
case 0:
for {
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRecord
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -389,6 +430,9 @@ func skipRecord(data []byte) (n int, err error) {
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRecord
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -409,6 +453,9 @@ func skipRecord(data []byte) (n int, err error) {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowRecord
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
......@@ -444,4 +491,5 @@ func skipRecord(data []byte) (n int, err error) {
var (
ErrInvalidLengthRecord = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowRecord = fmt.Errorf("proto: integer overflow")
)
......@@ -200,3 +200,28 @@ Apache License
See the License for the specific language governing permissions and
limitations under the License.
Third Party Sources Bundled
This project includes code derived from the MIT licensed naegelejd/go-acl
project. Here's a copy of its license:
Copyright (c) 2015 Joseph Naegele
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
......@@ -2,8 +2,6 @@
The API defined here is proposed, experimental, and (for now) subject to change at any time.
**Do not use it.**
If you think you want to use it, or for any other queries, contact <rkt-dev@googlegroups.com> or file an [issue](https://github.com/coreos/rkt/issues/new)
For more information, see:
......
......@@ -21,8 +21,6 @@
// The API defined here is proposed, experimental, //
// and (for now) subject to change at any time. //
// //
// Do not use it. //
// //
// If you think you want to use it, or for any other //
// queries, contact <rkt-dev@googlegroups.com> //
// or file an issue on github.com/coreos/rkt //
......@@ -234,6 +232,9 @@ message ImageFilter {
// If not empty, the images that have all of the annotations will be returned.
repeated KeyValue annotations = 8;
// If not empty, the images that have any of the exact full names will be returned.
repeated string full_names = 9;
}
// Info describes the information of rkt on the machine.
......
......@@ -20,8 +20,6 @@ import (
"fmt"
"os"
// Note that if your project uses Godep to manage dependencies, then
// you need to change following the import paths.
"github.com/coreos/rkt/api/v1alpha"
"golang.org/x/net/context"
"google.golang.org/grpc"
......
......@@ -230,6 +230,14 @@ var E_GogoprotoImport = &proto.ExtensionDesc{
Tag: "varint,63027,opt,name=gogoproto_import",
}
var E_ProtosizerAll = &proto.ExtensionDesc{
ExtendedType: (*google_protobuf.FileOptions)(nil),
ExtensionType: (*bool)(nil),
Field: 63028,
Name: "gogoproto.protosizer_all",
Tag: "varint,63028,opt,name=protosizer_all",
}
var E_GoprotoGetters = &proto.ExtensionDesc{
ExtendedType: (*google_protobuf.MessageOptions)(nil),
ExtensionType: (*bool)(nil),
......@@ -382,6 +390,14 @@ var E_GoprotoUnrecognized = &proto.ExtensionDesc{
Tag: "varint,64026,opt,name=goproto_unrecognized",
}
var E_Protosizer = &proto.ExtensionDesc{
ExtendedType: (*google_protobuf.MessageOptions)(nil),
ExtensionType: (*bool)(nil),
Field: 64028,
Name: "gogoproto.protosizer",
Tag: "varint,64028,opt,name=protosizer",
}
var E_Nullable = &proto.ExtensionDesc{
ExtendedType: (*google_protobuf.FieldOptions)(nil),
ExtensionType: (*bool)(nil),
......@@ -481,6 +497,7 @@ func init() {
proto.RegisterExtension(E_GoprotoExtensionsMapAll)
proto.RegisterExtension(E_GoprotoUnrecognizedAll)
proto.RegisterExtension(E_GogoprotoImport)
proto.RegisterExtension(E_ProtosizerAll)
proto.RegisterExtension(E_GoprotoGetters)
proto.RegisterExtension(E_GoprotoStringer)
proto.RegisterExtension(E_VerboseEqual)
......@@ -500,6 +517,7 @@ func init() {
proto.RegisterExtension(E_UnsafeUnmarshaler)
proto.RegisterExtension(E_GoprotoExtensionsMap)
proto.RegisterExtension(E_GoprotoUnrecognized)
proto.RegisterExtension(E_Protosizer)
proto.RegisterExtension(E_Nullable)
proto.RegisterExtension(E_Embed)
proto.RegisterExtension(E_Customtype)
......
......@@ -67,6 +67,8 @@ extend google.protobuf.FileOptions {
optional bool goproto_extensions_map_all = 63025;
optional bool goproto_unrecognized_all = 63026;
optional bool gogoproto_import = 63027;
optional bool protosizer_all = 63028;
}
extend google.protobuf.MessageOptions {
......@@ -93,6 +95,8 @@ extend google.protobuf.MessageOptions {
optional bool goproto_extensions_map = 64025;
optional bool goproto_unrecognized = 64026;
optional bool protosizer = 64028;
}
extend google.protobuf.FieldOptions {
......
......@@ -213,6 +213,10 @@ func IsSizer(file *google_protobuf.FileDescriptorProto, message *google_protobuf
return proto.GetBoolExtension(message.Options, E_Sizer, proto.GetBoolExtension(file.Options, E_SizerAll, false))
}
func IsProtoSizer(file *google_protobuf.FileDescriptorProto, message *google_protobuf.DescriptorProto) bool {
return proto.GetBoolExtension(message.Options, E_Protosizer, proto.GetBoolExtension(file.Options, E_ProtosizerAll, false))
}
func IsGoEnumStringer(file *google_protobuf.FileDescriptorProto, enum *google_protobuf.EnumDescriptorProto) bool {
return proto.GetBoolExtension(enum.Options, E_GoprotoEnumStringer, proto.GetBoolExtension(file.Options, E_GoprotoEnumStringerAll, true))
}
......
......@@ -80,7 +80,8 @@ var overwriters []map[string]gogoproto.EnableFunc = []map[string]gogoproto.Enabl
"verboseequal": gogoproto.HasVerboseEqual,
},
{
"size": gogoproto.IsSizer,
"size": gogoproto.IsSizer,
"protosizer": gogoproto.IsProtoSizer,
},
{
"unmarshaler": gogoproto.IsUnmarshaler,
......
......@@ -303,12 +303,12 @@ func wireToType(wire string) int {
panic("unreachable")
}
func (p *marshalto) mapField(numGen NumGen, fieldTyp descriptor.FieldDescriptorProto_Type, varName string) {
func (p *marshalto) mapField(numGen NumGen, fieldTyp descriptor.FieldDescriptorProto_Type, varName string, protoSizer bool) {
switch fieldTyp {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
p.callFixed64(p.mathPkg.Use(), `.Float64bits(`, varName, `)`)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(`, varName, `))`)
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
p.callFixed32(p.mathPkg.Use(), `.Float32bits(`, varName, `)`)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(`, varName, `))`)
case descriptor.FieldDescriptorProto_TYPE_INT64,
descriptor.FieldDescriptorProto_TYPE_UINT64,
descriptor.FieldDescriptorProto_TYPE_INT32,
......@@ -341,7 +341,11 @@ func (p *marshalto) mapField(numGen NumGen, fieldTyp descriptor.FieldDescriptorP
case descriptor.FieldDescriptorProto_TYPE_SINT64:
p.callVarint(`(uint64(`, varName, `) << 1) ^ uint64((`, varName, ` >> 63))`)
case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
p.callVarint(varName, `.Size()`)
if protoSizer {
p.callVarint(varName, `.ProtoSize()`)
} else {
p.callVarint(varName, `.Size()`)
}
p.P(`n`, numGen.Next(), `, err := `, varName, `.MarshalTo(data[i:])`)
p.P(`if err != nil {`)
p.In()
......@@ -371,6 +375,8 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
nullable := gogoproto.IsNullable(field)
repeated := field.IsRepeated()
required := field.IsRequired()
protoSizer := gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto)
if required && nullable {
p.P(`if m.`, fieldname, `== nil {`)
p.In()
......@@ -397,13 +403,13 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
}
switch *field.Type {
case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
if !p.unsafe {
if !p.unsafe || gogoproto.IsCastType(field) {
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 8`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(num)`)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`)
p.encodeFixed64("f" + numGen.Current())
p.Out()
p.P(`}`)
......@@ -411,7 +417,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(num)`)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float64bits(float64(num))`)
p.encodeFixed64("f" + numGen.Current())
p.Out()
p.P(`}`)
......@@ -419,15 +425,15 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(m.`+fieldname, `)`)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(m.`+fieldname, `)`)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(m.`+fieldname, `))`)
} else {
p.encodeKey(fieldNumber, wireType)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(*m.`+fieldname, `)`)
p.callFixed64(p.mathPkg.Use(), `.Float64bits(float64(*m.`+fieldname, `))`)
}
} else {
if packed {
......@@ -461,13 +467,13 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
}
}
case descriptor.FieldDescriptorProto_TYPE_FLOAT:
if !p.unsafe {
if !p.unsafe || gogoproto.IsCastType(field) {
if packed {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`len(m.`, fieldname, `) * 4`)
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(num)`)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`)
p.encodeFixed32("f" + numGen.Current())
p.Out()
p.P(`}`)
......@@ -475,7 +481,7 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
p.P(`for _, num := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(num)`)
p.P(`f`, numGen.Next(), ` := `, p.mathPkg.Use(), `.Float32bits(float32(num))`)
p.encodeFixed32("f" + numGen.Current())
p.Out()
p.P(`}`)
......@@ -483,15 +489,15 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
p.P(`if m.`, fieldname, ` != 0 {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(m.`+fieldname, `)`)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`)
p.Out()
p.P(`}`)
} else if !nullable {
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(m.`+fieldname, `)`)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(m.`+fieldname, `))`)
} else {
p.encodeKey(fieldNumber, wireType)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(*m.`+fieldname, `)`)
p.callFixed32(p.mathPkg.Use(), `.Float32bits(float32(*m.`+fieldname, `))`)
}
} else {
if packed {
......@@ -896,22 +902,30 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
} else if !nullable {
accessor = `(&v)`
}
p.P(`msgSize := `, accessor, `.Size()`)
if protoSizer {
p.P(`msgSize := `, accessor, `.ProtoSize()`)
} else {
p.P(`msgSize := `, accessor, `.Size()`)
}
sum = append(sum, `msgSize + sov`+p.localName+`(uint64(msgSize))`)
}
p.P(`mapSize := `, strings.Join(sum, " + "))
p.callVarint("mapSize")
p.encodeKey(1, wireToType(keywire))
p.mapField(numGen, m.KeyField.GetType(), "k")
p.mapField(numGen, m.KeyField.GetType(), "k", protoSizer)
p.encodeKey(2, wireToType(valuewire))
p.mapField(numGen, m.ValueField.GetType(), accessor)
p.mapField(numGen, m.ValueField.GetType(), accessor, protoSizer)
p.Out()
p.P(`}`)
} else if repeated {
p.P(`for _, msg := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callVarint("msg.Size()")
if protoSizer {
p.callVarint("msg.ProtoSize()")
} else {
p.callVarint("msg.Size()")
}
p.P(`n, err := msg.MarshalTo(data[i:])`)
p.P(`if err != nil {`)
p.In()
......@@ -923,7 +937,11 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
p.P(`}`)
} else {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`m.`, fieldname, `.Size()`)
if protoSizer {
p.callVarint(`m.`, fieldname, `.ProtoSize()`)
} else {
p.callVarint(`m.`, fieldname, `.Size()`)
}
p.P(`n`, numGen.Next(), `, err := m.`, fieldname, `.MarshalTo(data[i:])`)
p.P(`if err != nil {`)
p.In()
......@@ -960,7 +978,11 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
p.P(`for _, msg := range m.`, fieldname, ` {`)
p.In()
p.encodeKey(fieldNumber, wireType)
p.callVarint(`msg.Size()`)
if protoSizer {
p.callVarint(`msg.ProtoSize()`)
} else {
p.callVarint(`msg.Size()`)
}
p.P(`n, err := msg.MarshalTo(data[i:])`)
p.P(`if err != nil {`)
p.In()
......@@ -972,7 +994,11 @@ func (p *marshalto) generateField(proto3 bool, numGen NumGen, file *generator.Fi
p.P(`}`)
} else {
p.encodeKey(fieldNumber, wireType)
p.callVarint(`m.`, fieldname, `.Size()`)
if protoSizer {
p.callVarint(`m.`, fieldname, `.ProtoSize()`)
} else {
p.callVarint(`m.`, fieldname, `.Size()`)
}
p.P(`n`, numGen.Next(), `, err := m.`, fieldname, `.MarshalTo(data[i:])`)
p.P(`if err != nil {`)
p.In()
......@@ -1126,7 +1152,11 @@ func (p *marshalto) Generate(file *generator.FileDescriptor) {
p.P(`func (m *`, ccTypeName, `) Marshal() (data []byte, err error) {`)
p.In()
p.P(`size := m.Size()`)
if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) {
p.P(`size := m.ProtoSize()`)
} else {
p.P(`size := m.Size()`)
}
p.P(`data = make([]byte, size)`)
p.P(`n, err := m.MarshalTo(data)`)
p.P(`if err != nil {`)
......
......@@ -290,7 +290,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato
} else if field.IsMessage() || p.IsGroup(field) {
funcCall := getFuncCall(goTypName)
if field.IsRepeated() {
p.P(p.varGen.Next(), ` := r.Intn(10)`)
p.P(p.varGen.Next(), ` := r.Intn(5)`)
p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`)
p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`)
p.In()
......@@ -346,7 +346,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato
}
} else if field.IsBytes() {
if field.IsRepeated() {
p.P(p.varGen.Next(), ` := r.Intn(100)`)
p.P(p.varGen.Next(), ` := r.Intn(10)`)
p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`)
p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`)
p.In()
......@@ -387,7 +387,7 @@ func (p *plugin) GenerateField(file *generator.FileDescriptor, message *generato
} else {
typName := generator.GoTypeToName(goTyp)
if field.IsRepeated() {
p.P(p.varGen.Next(), ` := r.Intn(100)`)
p.P(p.varGen.Next(), ` := r.Intn(10)`)
p.P(`this.`, fieldname, ` = make(`, goTyp, `, `, p.varGen.Current(), `)`)
p.P(`for i := 0; i < `, p.varGen.Current(), `; i++ {`)
p.In()
......
......@@ -25,7 +25,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*
The size plugin generates a Size method for each message.
The size plugin generates a Size or ProtoSize method for each message.
This is useful with the MarshalTo method generated by the marshalto plugin and the
gogoproto.marshaler and gogoproto.marshaler_all extensions.
......@@ -33,6 +33,8 @@ It is enabled by the following extensions:
- sizer
- sizer_all
- protosizer
- protosizer_all
The size plugin also generates a test given it is enabled using one of the following extensions:
......@@ -195,7 +197,7 @@ func (p *size) sizeZigZag() {
}`)
}
func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto) {
func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, message *generator.Descriptor, field *descriptor.FieldDescriptorProto, sizeName string) {
fieldname := p.GetOneOfFieldName(message, field)
nullable := gogoproto.IsNullable(field)
repeated := field.IsRepeated()
......@@ -393,17 +395,17 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag
p.P(`if v != nil {`)
p.In()
if valuegoTyp != valuegoAliasTyp {
p.P(`l = ((`, valuegoTyp, `)(v)).Size()`)
p.P(`l = ((`, valuegoTyp, `)(v)).`, sizeName, `()`)
} else {
p.P(`l = v.Size()`)
p.P(`l = v.`, sizeName, `()`)
}
p.Out()
p.P(`}`)
} else {
if valuegoTyp != valuegoAliasTyp {
p.P(`l = ((*`, valuegoTyp, `)(&v)).Size()`)
p.P(`l = ((*`, valuegoTyp, `)(&v)).`, sizeName, `()`)
} else {
p.P(`l = v.Size()`)
p.P(`l = v.`, sizeName, `()`)
}
}
sum = append(sum, `l+sov`+p.localName+`(uint64(l))`)
......@@ -415,12 +417,12 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag
} else if repeated {
p.P(`for _, e := range m.`, fieldname, ` { `)
p.In()
p.P(`l=e.Size()`)
p.P(`l=e.`, sizeName, `()`)
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
p.Out()
p.P(`}`)
} else {
p.P(`l=m.`, fieldname, `.Size()`)
p.P(`l=m.`, fieldname, `.`, sizeName, `()`)
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
}
case descriptor.FieldDescriptorProto_TYPE_BYTES:
......@@ -447,12 +449,12 @@ func (p *size) generateField(proto3 bool, file *generator.FileDescriptor, messag
if repeated {
p.P(`for _, e := range m.`, fieldname, ` { `)
p.In()
p.P(`l=e.Size()`)
p.P(`l=e.`, sizeName, `()`)
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
p.Out()
p.P(`}`)
} else {
p.P(`l=m.`, fieldname, `.Size()`)
p.P(`l=m.`, fieldname, `.`, sizeName, `()`)
p.P(`n+=`, strconv.Itoa(key), `+l+sov`, p.localName, `(uint64(l))`)
}
}
......@@ -501,7 +503,12 @@ func (p *size) Generate(file *generator.FileDescriptor) {
protoPkg = p.NewImport("github.com/golang/protobuf/proto")
}
for _, message := range file.Messages() {
if !gogoproto.IsSizer(file.FileDescriptorProto, message.DescriptorProto) {
sizeName := ""
if gogoproto.IsSizer(file.FileDescriptorProto, message.DescriptorProto) {
sizeName = "Size"
} else if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) {
sizeName = "ProtoSize"
} else {
continue
}
if message.DescriptorProto.GetOptions().GetMapEntry() {
......@@ -509,7 +516,7 @@ func (p *size) Generate(file *generator.FileDescriptor) {
}
p.atleastOne = true
ccTypeName := generator.CamelCaseSlice(message.TypeName())
p.P(`func (m *`, ccTypeName, `) Size() (n int) {`)
p.P(`func (m *`, ccTypeName, `) `, sizeName, `() (n int) {`)
p.In()
p.P(`var l int`)
p.P(`_ = l`)
......@@ -518,7 +525,7 @@ func (p *size) Generate(file *generator.FileDescriptor) {
oneof := field.OneofIndex != nil
if !oneof {
proto3 := gogoproto.IsProto3(file.FileDescriptorProto)
p.generateField(proto3, file, message, field)
p.generateField(proto3, file, message, field, sizeName)
} else {
fieldname := p.GetFieldName(message, field)
if _, ok := oneofs[fieldname]; ok {
......@@ -528,7 +535,7 @@ func (p *size) Generate(file *generator.FileDescriptor) {
}
p.P(`if m.`, fieldname, ` != nil {`)
p.In()
p.P(`n+=m.`, fieldname, `.Size()`)
p.P(`n+=m.`, fieldname, `.`, sizeName, `()`)
p.Out()
p.P(`}`)
}
......@@ -564,12 +571,12 @@ func (p *size) Generate(file *generator.FileDescriptor) {
continue
}
ccTypeName := p.OneOfTypeName(message, f)
p.P(`func (m *`, ccTypeName, `) Size() (n int) {`)
p.P(`func (m *`, ccTypeName, `) `, sizeName, `() (n int) {`)
p.In()
p.P(`var l int`)
p.P(`_ = l`)
vanity.TurnOffNullableForNativeTypesWithoutDefaultsOnly(f)
p.generateField(false, file, message, f)
p.generateField(false, file, message, f, sizeName)
p.P(`return n`)
p.Out()
p.P(`}`)
......
......@@ -51,7 +51,12 @@ func (p *test) Generate(imports generator.PluginImports, file *generator.FileDes
}
for _, message := range file.Messages() {
ccTypeName := generator.CamelCaseSlice(message.TypeName())
if !gogoproto.IsSizer(file.FileDescriptorProto, message.DescriptorProto) {
sizeName := ""
if gogoproto.IsSizer(file.FileDescriptorProto, message.DescriptorProto) {
sizeName = "Size"
} else if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) {
sizeName = "ProtoSize"
} else {
continue
}
if message.DescriptorProto.GetOptions().GetMapEntry() {
......@@ -60,7 +65,7 @@ func (p *test) Generate(imports generator.PluginImports, file *generator.FileDes
if gogoproto.HasTestGen(file.FileDescriptorProto, message.DescriptorProto) {
used = true
p.P(`func Test`, ccTypeName, `Size(t *`, testingPkg.Use(), `.T) {`)
p.P(`func Test`, ccTypeName, sizeName, `(t *`, testingPkg.Use(), `.T) {`)
p.In()
p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
......@@ -72,7 +77,7 @@ func (p *test) Generate(imports generator.PluginImports, file *generator.FileDes
p.P(`t.Fatalf("seed = %d, err = %v", seed, err)`)
p.Out()
p.P(`}`)
p.P(`size := p.Size()`)
p.P(`size := p.`, sizeName, `()`)
p.P(`if len(data) != size {`)
p.In()
p.P(`t.Errorf("seed = %d, size %v != marshalled size %v", seed, size, len(data))`)
......@@ -96,7 +101,7 @@ func (p *test) Generate(imports generator.PluginImports, file *generator.FileDes
if gogoproto.HasBenchGen(file.FileDescriptorProto, message.DescriptorProto) {
used = true
p.P(`func Benchmark`, ccTypeName, `Size(b *`, testingPkg.Use(), `.B) {`)
p.P(`func Benchmark`, ccTypeName, sizeName, `(b *`, testingPkg.Use(), `.B) {`)
p.In()
p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(616))`)
p.P(`total := 0`)
......@@ -109,7 +114,7 @@ func (p *test) Generate(imports generator.PluginImports, file *generator.FileDes
p.P(`b.ResetTimer()`)
p.P(`for i := 0; i < b.N; i++ {`)
p.In()
p.P(`total += pops[i%1000].Size()`)
p.P(`total += pops[i%1000].`, sizeName, `()`)
p.Out()
p.P(`}`)
p.P(`b.SetBytes(int64(total / b.N))`)
......
......@@ -341,7 +341,11 @@ func (p *testProto) Generate(imports generator.PluginImports, file *generator.Fi
p.P(`seed := `, timePkg.Use(), `.Now().UnixNano()`)
p.P(`popr := `, randPkg.Use(), `.New(`, randPkg.Use(), `.NewSource(seed))`)
p.P(`p := NewPopulated`, ccTypeName, `(popr, false)`)
p.P(`size := p.Size()`)
if gogoproto.IsProtoSizer(file.FileDescriptorProto, message.DescriptorProto) {
p.P(`size := p.ProtoSize()`)
} else {
p.P(`size := p.Size()`)
}
p.P(`data := make([]byte, size)`)
p.P(`for i := range data {`)
p.In()
......
......@@ -419,7 +419,7 @@ func (p *unmarshal) noStarOrSliceType(msg *generator.Descriptor, field *descript
return typ
}
func (p *unmarshal) field(file *descriptor.FileDescriptorProto, msg *generator.Descriptor, field *descriptor.FieldDescriptorProto, fieldname string, proto3 bool) {
func (p *unmarshal) field(file *generator.FileDescriptor, msg *generator.Descriptor, field *descriptor.FieldDescriptorProto, fieldname string, proto3 bool) {
repeated := field.IsRepeated()
nullable := gogoproto.IsNullable(field)
typ := p.noStarOrSliceType(msg, field)
......@@ -676,7 +676,7 @@ func (p *unmarshal) field(file *descriptor.FileDescriptorProto, msg *generator.D
p.Out()
p.P(`}`)
p.P(`m.`, fieldname, ` = &`, p.OneOfTypeName(msg, field), `{v}`)
} else if generator.IsMap(file, field) {
} else if generator.IsMap(file.FileDescriptorProto, field) {
m := p.GoMapType(nil, field)
keygoTyp, _ := p.GoType(nil, m.KeyField)
......@@ -773,7 +773,12 @@ func (p *unmarshal) field(file *descriptor.FileDescriptorProto, msg *generator.D
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `, make([]byte, postIndex-iNdEx))`)
p.P(`copy(m.`, fieldname, `[len(m.`, fieldname, `)-1], data[iNdEx:postIndex])`)
} else {
p.P(`m.`, fieldname, ` = append([]byte{}`, `, data[iNdEx:postIndex]...)`)
p.P(`m.`, fieldname, ` = append(m.`, fieldname, `[:0] , data[iNdEx:postIndex]...)`)
p.P(`if m.`, fieldname, ` == nil {`)
p.In()
p.P(`m.`, fieldname, ` = []byte{}`)
p.Out()
p.P(`}`)
}
} else {
_, ctyp, err := generator.GetCustomType(field)
......@@ -1061,13 +1066,13 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) {
p.P(`}`)
p.P(`for iNdEx < postIndex {`)
p.In()
p.field(file.FileDescriptorProto, message, field, fieldname, false)
p.field(file, message, field, fieldname, false)
p.Out()
p.P(`}`)
p.Out()
p.P(`} else if wireType == `, strconv.Itoa(wireType), `{`)
p.In()
p.field(file.FileDescriptorProto, message, field, fieldname, false)
p.field(file, message, field, fieldname, false)
p.Out()
p.P(`} else {`)
p.In()
......@@ -1080,7 +1085,7 @@ func (p *unmarshal) Generate(file *generator.FileDescriptor) {
p.P(`return ` + fmtPkg.Use() + `.Errorf("proto: wrong wireType = %d for field ` + errFieldname + `", wireType)`)
p.Out()
p.P(`}`)
p.field(file.FileDescriptorProto, message, field, fieldname, proto3)
p.field(file, message, field, fieldname, proto3)
}
if field.IsRequired() {
......
......@@ -601,7 +601,7 @@ func (g *Generator) CommandLineParameters(parameter string) {
if pluginList == "none" {
pluginList = ""
}
gogoPluginNames := []string{"unmarshal", "unsafeunmarshaler", "union", "stringer", "size", "populate", "marshalto", "unsafemarshaler", "gostring", "face", "equal", "enumstringer", "embedcheck", "description", "defaultcheck", "oneofcheck"}
gogoPluginNames := []string{"unmarshal", "unsafeunmarshaler", "union", "stringer", "size", "protosizer", "populate", "marshalto", "unsafemarshaler", "gostring", "face", "equal", "enumstringer", "embedcheck", "description", "defaultcheck", "oneofcheck"}
pluginList = strings.Join(append(gogoPluginNames, pluginList), "+")
if pluginList != "" {
// Amend the set of plugins.
......@@ -1857,11 +1857,11 @@ var methodNames = [...]string{
"ExtensionRangeArray",
"ExtensionMap",
"Descriptor",
"Size",
"MarshalTo",
"Equal",
"VerboseEqual",
"GoString",
"ProtoSize",
}
// Generate the type and default constant definitions for this Descriptor.
......@@ -1875,6 +1875,9 @@ func (g *Generator) generateMessage(message *Descriptor) {
for _, n := range methodNames {
usedNames[n] = true
}
if !gogoproto.IsProtoSizer(message.file, message.DescriptorProto) {
usedNames["Size"] = true
}
fieldNames := make(map[*descriptor.FieldDescriptorProto]string)
fieldGetterNames := make(map[*descriptor.FieldDescriptorProto]string)
fieldTypes := make(map[*descriptor.FieldDescriptorProto]string)
......@@ -2210,6 +2213,9 @@ func (g *Generator) generateMessage(message *Descriptor) {
if gogoproto.IsSizer(g.file.FileDescriptorProto, message.DescriptorProto) {
g.P(`Size() int`)
}
if gogoproto.IsProtoSizer(g.file.FileDescriptorProto, message.DescriptorProto) {
g.P(`ProtoSize() int`)
}
g.Out()
g.P("}")
}
......
......@@ -181,6 +181,11 @@ func (g *Generator) GetFieldName(message *Descriptor, field *descriptor.FieldDes
return fieldname + "_"
}
}
if !gogoproto.IsProtoSizer(message.file, message.DescriptorProto) {
if fieldname == "Size" {
return fieldname + "_"
}
}
return fieldname
}
......@@ -198,6 +203,11 @@ func (g *Generator) GetOneOfFieldName(message *Descriptor, field *descriptor.Fie
return fieldname + "_"
}
}
if !gogoproto.IsProtoSizer(message.file, message.DescriptorProto) {
if fieldname == "Size" {
return fieldname + "_"
}
}
return fieldname
}
......
......@@ -39,5 +39,5 @@ test: install generate-test-pbs
generate-test-pbs:
make install
make -C testdata
make -C proto3_proto
protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata:. proto3_proto/proto3.proto
make
......@@ -29,8 +29,8 @@
// (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.
// TODO: MessageSet and RawMessage.
// Protocol buffer deep copy and merge.
// TODO: RawMessage.
package proto
......@@ -75,12 +75,13 @@ func Merge(dst, src Message) {
}
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))
mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
}
if emIn, ok := in.Addr().Interface().(extendableProto); ok {
......@@ -98,7 +99,10 @@ func mergeStruct(out, in reflect.Value) {
}
}
func mergeAny(out, in reflect.Value) {
// 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() {
......@@ -112,7 +116,21 @@ func mergeAny(out, in reflect.Value) {
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
......@@ -127,7 +145,7 @@ func mergeAny(out, in reflect.Value) {
switch elemKind {
case reflect.Ptr:
val = reflect.New(in.Type().Elem().Elem())
mergeAny(val, in.MapIndex(key))
mergeAny(val, in.MapIndex(key), false, nil)
case reflect.Slice:
val = in.MapIndex(key)
val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
......@@ -143,13 +161,21 @@ func mergeAny(out, in reflect.Value) {
if out.IsNil() {
out.Set(reflect.New(in.Elem().Type()))
}
mergeAny(out.Elem(), in.Elem())
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.
......@@ -167,7 +193,7 @@ func mergeAny(out, in reflect.Value) {
default:
for i := 0; i < n; i++ {
x := reflect.Indirect(reflect.New(in.Type().Elem()))
mergeAny(x, in.Index(i))
mergeAny(x, in.Index(i), false, nil)
out.Set(reflect.Append(out, x))
}
}
......@@ -184,7 +210,7 @@ func mergeExtension(out, in map[int32]Extension) {
eOut := Extension{desc: eIn.desc}
if eIn.value != nil {
v := reflect.New(reflect.TypeOf(eIn.value)).Elem()
mergeAny(v, reflect.ValueOf(eIn.value))
mergeAny(v, reflect.ValueOf(eIn.value), false, nil)
eOut.value = v.Interface()
}
if eIn.enc != nil {
......
......@@ -46,6 +46,10 @@ import (
// 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.
......@@ -314,6 +318,24 @@ func UnmarshalMerge(buf []byte, pb Message) error {
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
......@@ -377,6 +399,20 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group
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
}
......@@ -518,9 +554,7 @@ func (o *Buffer) dec_string(p *Properties, base structPointer) error {
if err != nil {
return err
}
sp := new(string)
*sp = s
*structPointer_String(base, p.field) = sp
*structPointer_String(base, p.field) = &s
return nil
}
......@@ -563,9 +597,13 @@ func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error
return err
}
nb := int(nn) // number of bytes of encoded bools
fin := o.index + nb
if fin < o.index {
return errOverflow
}
y := *v
for i := 0; i < nb; i++ {
for o.index < fin {
u, err := p.valDec(o)
if err != nil {
return err
......@@ -677,7 +715,7 @@ func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
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_Map(base, p.field, p.mtype) // *map[K]V
mptr := structPointer_NewAt(base, p.field, p.mtype) // *map[K]V
if mptr.Elem().IsNil() {
mptr.Elem().Set(reflect.MakeMap(mptr.Type().Elem()))
}
......@@ -729,8 +767,14 @@ func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
return fmt.Errorf("proto: bad map data tag %d", raw[0])
}
}
keyelem, valelem := keyptr.Elem(), valptr.Elem()
if !keyelem.IsValid() || !valelem.IsValid() {
// We did not decode the key or the value in the map entry.
// Either way, it's an invalid map entry.
return fmt.Errorf("proto: bad map data: missing key/val")
}
v.SetMapIndex(keyptr.Elem(), valptr.Elem())
v.SetMapIndex(keyelem, valelem)
return nil
}
......
......@@ -60,9 +60,9 @@ func (e *RequiredNotSetError) Error() string {
}
var (
// ErrRepeatedHasNil is the error returned if Marshal is called with
// errRepeatedHasNil is the error returned if Marshal is called with
// a struct with a repeated field containing a nil element.
ErrRepeatedHasNil = errors.New("proto: repeated field has nil element")
errRepeatedHasNil = errors.New("proto: repeated field has nil element")
// ErrNil is the error returned if Marshal is called with nil.
ErrNil = errors.New("proto: Marshal called with nil")
......@@ -105,6 +105,11 @@ func (p *Buffer) EncodeVarint(x uint64) error {
return nil
}
// SizeVarint returns the varint encoding size of an integer.
func SizeVarint(x uint64) int {
return sizeVarint(x)
}
func sizeVarint(x uint64) (n int) {
for {
n++
......@@ -228,6 +233,20 @@ func Marshal(pb Message) ([]byte, error) {
return p.buf, err
}
// EncodeMessage writes the protocol buffer to the Buffer,
// prefixed by a varint-encoded length.
func (p *Buffer) EncodeMessage(pb Message) error {
t, base, err := getbase(pb)
if structPointer_IsNil(base) {
return ErrNil
}
if err == nil {
var state errorState
err = p.enc_len_struct(GetProperties(t.Elem()), base, &state)
}
return err
}
// Marshal takes the protocol buffer
// and encodes it into the wire format, writing the result to the
// Buffer.
......@@ -318,7 +337,7 @@ func size_bool(p *Properties, base structPointer) int {
func size_proto3_bool(p *Properties, base structPointer) int {
v := *structPointer_BoolVal(base, p.field)
if !v {
if !v && !p.oneof {
return 0
}
return len(p.tagcode) + 1 // each bool takes exactly one byte
......@@ -361,7 +380,7 @@ func size_int32(p *Properties, base structPointer) (n int) {
func size_proto3_int32(p *Properties, base structPointer) (n int) {
v := structPointer_Word32Val(base, p.field)
x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
if x == 0 {
if x == 0 && !p.oneof {
return 0
}
n += len(p.tagcode)
......@@ -407,7 +426,7 @@ func size_uint32(p *Properties, base structPointer) (n int) {
func size_proto3_uint32(p *Properties, base structPointer) (n int) {
v := structPointer_Word32Val(base, p.field)
x := word32Val_Get(v)
if x == 0 {
if x == 0 && !p.oneof {
return 0
}
n += len(p.tagcode)
......@@ -452,7 +471,7 @@ func size_int64(p *Properties, base structPointer) (n int) {
func size_proto3_int64(p *Properties, base structPointer) (n int) {
v := structPointer_Word64Val(base, p.field)
x := word64Val_Get(v)
if x == 0 {
if x == 0 && !p.oneof {
return 0
}
n += len(p.tagcode)
......@@ -495,7 +514,7 @@ func size_string(p *Properties, base structPointer) (n int) {
func size_proto3_string(p *Properties, base structPointer) (n int) {
v := *structPointer_StringVal(base, p.field)
if v == "" {
if v == "" && !p.oneof {
return 0
}
n += len(p.tagcode)
......@@ -529,7 +548,7 @@ func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
}
o.buf = append(o.buf, p.tagcode...)
o.EncodeRawBytes(data)
return nil
return state.err
}
o.buf = append(o.buf, p.tagcode...)
......@@ -667,7 +686,7 @@ func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error
func size_slice_byte(p *Properties, base structPointer) (n int) {
s := *structPointer_Bytes(base, p.field)
if s == nil {
if s == nil && !p.oneof {
return 0
}
n += len(p.tagcode)
......@@ -677,7 +696,7 @@ func size_slice_byte(p *Properties, base structPointer) (n int) {
func size_proto3_slice_byte(p *Properties, base structPointer) (n int) {
s := *structPointer_Bytes(base, p.field)
if len(s) == 0 {
if len(s) == 0 && !p.oneof {
return 0
}
n += len(p.tagcode)
......@@ -939,7 +958,7 @@ func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) err
for i := 0; i < l; i++ {
structp := s.Index(i)
if structPointer_IsNil(structp) {
return ErrRepeatedHasNil
return errRepeatedHasNil
}
// Can the object marshal itself?
......@@ -958,7 +977,7 @@ func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) err
err := o.enc_len_struct(p.sprop, structp, &state)
if err != nil && !state.shouldContinue(err, nil) {
if err == ErrNil {
return ErrRepeatedHasNil
return errRepeatedHasNil
}
return err
}
......@@ -1001,7 +1020,7 @@ func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error
for i := 0; i < l; i++ {
b := s.Index(i)
if structPointer_IsNil(b) {
return ErrRepeatedHasNil
return errRepeatedHasNil
}
o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
......@@ -1010,7 +1029,7 @@ func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error
if err != nil && !state.shouldContinue(err, nil) {
if err == ErrNil {
return ErrRepeatedHasNil
return errRepeatedHasNil
}
return err
}
......@@ -1084,7 +1103,7 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error {
repeated MapFieldEntry map_field = N;
*/
v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V
v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V
if v.Len() == 0 {
return nil
}
......@@ -1101,11 +1120,15 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error {
return nil
}
keys := v.MapKeys()
sort.Sort(mapKeys(keys))
for _, key := range keys {
// Don't sort map keys. It is not required by the spec, and C++ doesn't do it.
for _, key := range v.MapKeys() {
val := v.MapIndex(key)
// The only illegal map entry values are nil message pointers.
if val.Kind() == reflect.Ptr && val.IsNil() {
return errors.New("proto: map has nil element")
}
keycopy.Set(key)
valcopy.Set(val)
......@@ -1118,7 +1141,7 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error {
}
func size_new_map(p *Properties, base structPointer) int {
v := structPointer_Map(base, p.field, p.mtype).Elem() // map[K]V
v := structPointer_NewAt(base, p.field, p.mtype).Elem() // map[K]V
keycopy, valcopy, keybase, valbase := mapEncodeScratch(p.mtype)
......@@ -1128,10 +1151,12 @@ func size_new_map(p *Properties, base structPointer) int {
keycopy.Set(key)
valcopy.Set(val)
// Tag codes are two bytes per map entry.
n += 2
n += p.mkeyprop.size(p.mkeyprop, keybase)
n += p.mvalprop.size(p.mvalprop, valbase)
// Tag codes for key and val are the responsibility of the sub-sizer.
keysize := p.mkeyprop.size(p.mkeyprop, keybase)
valsize := p.mvalprop.size(p.mvalprop, valbase)
entry := keysize + valsize
// Add on tag code and length of map entry itself.
n += len(p.tagcode) + sizeVarint(uint64(entry)) + entry
}
return n
}
......@@ -1184,6 +1209,9 @@ func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error {
if p.Required && state.err == nil {
state.err = &RequiredNotSetError{p.Name}
}
} else if err == errRepeatedHasNil {
// Give more context to nil values in repeated fields.
return errors.New("repeated field " + p.OrigName + " has nil element")
} else if !state.shouldContinue(err, p) {
return err
}
......@@ -1191,6 +1219,14 @@ func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error {
}
}
// Do oneof fields.
if prop.oneofMarshaler != nil {
m := structPointer_Interface(base, prop.stype).(Message)
if err := prop.oneofMarshaler(m, o); err != nil {
return err
}
}
// Add unrecognized fields at the end.
if prop.unrecField.IsValid() {
v := *structPointer_Bytes(base, prop.unrecField)
......@@ -1216,6 +1252,12 @@ func size_struct(prop *StructProperties, base structPointer) (n int) {
n += len(v)
}
// Factor in any oneof fields.
if prop.oneofSizer != nil {
m := structPointer_Interface(base, prop.stype).(Message)
n += prop.oneofSizer(m)
}
return
}
......
......@@ -30,7 +30,6 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Protocol buffer comparison.
// TODO: MessageSet.
package proto
......@@ -51,7 +50,9 @@ Equality is defined in this way:
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.
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 (a "bytes" field,
although represented by []byte, is not a repeated field)
......@@ -89,6 +90,7 @@ func Equal(a, b Message) bool {
// 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_") {
......@@ -114,7 +116,7 @@ func equalStruct(v1, v2 reflect.Value) bool {
}
f1, f2 = f1.Elem(), f2.Elem()
}
if !equalAny(f1, f2) {
if !equalAny(f1, f2, sprop.Prop[i]) {
return false
}
}
......@@ -141,7 +143,8 @@ func equalStruct(v1, v2 reflect.Value) bool {
}
// v1 and v2 are known to have the same type.
func equalAny(v1, v2 reflect.Value) bool {
// 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)
......@@ -154,6 +157,17 @@ func equalAny(v1, v2 reflect.Value) bool {
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
......@@ -164,16 +178,22 @@ func equalAny(v1, v2 reflect.Value) bool {
// This key was not found in the second map.
return false
}
if !equalAny(v1.MapIndex(key), val2) {
if !equalAny(v1.MapIndex(key), val2, nil) {
return false
}
}
return true
case reflect.Ptr:
return equalAny(v1.Elem(), v2.Elem())
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
}
......@@ -184,7 +204,7 @@ func equalAny(v1, v2 reflect.Value) bool {
return false
}
for i := 0; i < v1.Len(); i++ {
if !equalAny(v1.Index(i), v2.Index(i)) {
if !equalAny(v1.Index(i), v2.Index(i), prop) {
return false
}
}
......@@ -219,7 +239,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
if m1 != nil && m2 != nil {
// Both are unencoded.
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
return false
}
continue
......@@ -247,7 +267,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
return false
}
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
return false
}
}
......
......@@ -37,6 +37,7 @@ package proto
import (
"errors"
"fmt"
"reflect"
"strconv"
"sync"
......@@ -221,7 +222,7 @@ func ClearExtension(pb extendableProto, extension *ExtensionDesc) {
}
// GetExtension parses and returns the given extension of pb.
// If the extension is not present it returns ErrMissingExtension.
// If the extension is not present and has no default value it returns ErrMissingExtension.
func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, error) {
if err := checkExtensionTypes(pb, extension); err != nil {
return nil, err
......@@ -230,8 +231,11 @@ func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, er
emap := pb.ExtensionMap()
e, ok := emap[extension.Field]
if !ok {
return nil, ErrMissingExtension
// 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 {
......@@ -257,12 +261,46 @@ func GetExtension(pb extendableProto, extension *ExtensionDesc) (interface{}, er
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)
rep := extension.repeated()
props := extensionProperties(extension)
......@@ -284,7 +322,7 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
return nil, err
}
if !rep || o.index >= len(o.buf) {
if o.index >= len(o.buf) {
break
}
}
......@@ -321,6 +359,14 @@ func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{
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)
}
pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
return nil
......
......@@ -44,11 +44,11 @@ import (
"sort"
)
// ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID.
// 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")
var errNoMessageTypeID = errors.New("proto does not have a message type ID")
// The first two types (_MessageSet_Item and MessageSet)
// 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 {
......@@ -58,27 +58,20 @@ var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
// }
// 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.
//
// When a proto1 proto has a field that looks like:
// optional message<MessageSet> info = 3;
// the protocol compiler produces a field in the generated struct that looks like:
// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"`
// The package is automatically inserted so there is no need for that proto file to
// import 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 {
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)
// 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.
......@@ -86,7 +79,7 @@ type messageTypeIder interface {
MessageTypeId() int32
}
func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
func (ms *messageSet) find(pb Message) *_MessageSet_Item {
mti, ok := pb.(messageTypeIder)
if !ok {
return nil
......@@ -100,24 +93,24 @@ func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
return nil
}
func (ms *MessageSet) Has(pb Message) bool {
func (ms *messageSet) Has(pb Message) bool {
if ms.find(pb) != nil {
return true
}
return false
}
func (ms *MessageSet) Unmarshal(pb Message) error {
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 errNoMessageTypeID
}
return nil // TODO: return error instead?
}
func (ms *MessageSet) Marshal(pb Message) error {
func (ms *messageSet) Marshal(pb Message) error {
msg, err := Marshal(pb)
if err != nil {
return err
......@@ -130,7 +123,7 @@ func (ms *MessageSet) Marshal(pb Message) error {
mti, ok := pb.(messageTypeIder)
if !ok {
return ErrNoMessageTypeId
return errNoMessageTypeID
}
mtid := mti.MessageTypeId()
......@@ -141,9 +134,9 @@ func (ms *MessageSet) Marshal(pb Message) error {
return nil
}
func (ms *MessageSet) Reset() { *ms = MessageSet{} }
func (ms *MessageSet) String() string { return CompactTextString(ms) }
func (*MessageSet) ProtoMessage() {}
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.
......@@ -169,7 +162,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
}
sort.Ints(ids)
ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
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.
......@@ -186,7 +179,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
// 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, m map[int32]Extension) error {
ms := new(MessageSet)
ms := new(messageSet)
if err := Unmarshal(buf, ms); err != nil {
return err
}
......
......@@ -29,7 +29,7 @@
// (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,!appenginevm
// +build appengine
// 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
......@@ -144,8 +144,8 @@ func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
return structPointer_ifield(p, f).(*map[int32]Extension)
}
// Map returns the reflect.Value for the address of a map field in the struct.
func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value {
// 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()
}
......
......@@ -29,7 +29,7 @@
// (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 appenginevm
// +build !appengine
// This file contains the implementation of the proto field accesses using package unsafe.
......@@ -130,8 +130,8 @@ func structPointer_ExtMap(p structPointer, f field) *map[int32]Extension {
return (*map[int32]Extension)(unsafe.Pointer(uintptr(p) + uintptr(f)))
}
// Map returns the reflect.Value for the address of a map field in the struct.
func structPointer_Map(p structPointer, f field, typ reflect.Type) reflect.Value {
// 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)))
}
......
......@@ -37,6 +37,7 @@ package proto
import (
"fmt"
"log"
"os"
"reflect"
"sort"
......@@ -84,6 +85,15 @@ 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.
......@@ -132,6 +142,22 @@ type StructProperties struct {
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.
......@@ -156,6 +182,7 @@ type Properties struct {
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
......@@ -208,6 +235,9 @@ func (p *Properties) String() string {
if p.proto3 {
s += ",proto3"
}
if p.oneof {
s += ",oneof"
}
if len(p.Enum) > 0 {
s += ",enum=" + p.Enum
}
......@@ -284,6 +314,8 @@ func (p *Properties) Parse(s string) {
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
......@@ -440,7 +472,12 @@ func (p *Properties) setEncAndDec(typ reflect.Type, f *reflect.StructField, lock
p.enc = (*Buffer).enc_slice_byte
p.dec = (*Buffer).dec_slice_byte
p.size = size_slice_byte
if p.proto3 {
// This is a []byte, which is either a bytes field,
// or the value of a map field. In the latter case,
// we always encode an empty []byte, so we should not
// use the proto3 enc/size funcs.
// f == nil iff this is the key/value of a map field.
if p.proto3 && f != nil {
p.enc = (*Buffer).enc_proto3_slice_byte
p.size = size_proto3_slice_byte
}
......@@ -595,7 +632,7 @@ func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructF
}
var (
mutex sync.Mutex
propertiesMu sync.RWMutex
propertiesMap = make(map[reflect.Type]*StructProperties)
)
......@@ -605,13 +642,26 @@ func GetProperties(t reflect.Type) *StructProperties {
if t.Kind() != reflect.Struct {
panic("proto: type must have kind struct")
}
mutex.Lock()
sprop := getPropertiesLocked(t)
mutex.Unlock()
// 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 mutex is held.
// getPropertiesLocked requires that propertiesMu is held.
func getPropertiesLocked(t reflect.Type) *StructProperties {
if prop, ok := propertiesMap[t]; ok {
if collectStats {
......@@ -647,6 +697,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
if f.Name == "XXX_unrecognized" { // special case
prop.unrecField = toField(&f)
}
oneof := f.Tag.Get("protobuf_oneof") != "" // special case
prop.Prop[i] = p
prop.order[i] = i
if debug {
......@@ -656,7 +707,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
}
print("\n")
}
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && !oneof {
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
}
}
......@@ -664,6 +715,41 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
// 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
......@@ -722,3 +808,35 @@ func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[
}
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 { 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] }
# Go support for Protocol Buffers - Google's data interchange format
#
# Copyright 2014 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.
include ../../Make.protobuf
all: regenerate
regenerate:
rm -f proto3.pb.go
make proto3.pb.go
# The following rules are just aids to development. Not needed for typical testing.
diff: regenerate
git diff proto3.pb.go
// Code generated by protoc-gen-go.
// source: proto3_proto/proto3.proto
// DO NOT EDIT!
/*
Package proto3_proto is a generated protocol buffer package.
It is generated from these files:
proto3_proto/proto3.proto
It has these top-level messages:
Message
Nested
MessageWithMap
*/
package proto3_proto
import proto "github.com/golang/protobuf/proto"
import testdata "github.com/golang/protobuf/proto/testdata"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
type Message_Humour int32
const (
Message_UNKNOWN Message_Humour = 0
Message_PUNS Message_Humour = 1
Message_SLAPSTICK Message_Humour = 2
Message_BILL_BAILEY Message_Humour = 3
)
var Message_Humour_name = map[int32]string{
0: "UNKNOWN",
1: "PUNS",
2: "SLAPSTICK",
3: "BILL_BAILEY",
}
var Message_Humour_value = map[string]int32{
"UNKNOWN": 0,
"PUNS": 1,
"SLAPSTICK": 2,
"BILL_BAILEY": 3,
}
func (x Message_Humour) String() string {
return proto.EnumName(Message_Humour_name, int32(x))
}
type Message struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
Hilarity Message_Humour `protobuf:"varint,2,opt,name=hilarity,enum=proto3_proto.Message_Humour" json:"hilarity,omitempty"`
HeightInCm uint32 `protobuf:"varint,3,opt,name=height_in_cm" json:"height_in_cm,omitempty"`
Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"`
ResultCount int64 `protobuf:"varint,7,opt,name=result_count" json:"result_count,omitempty"`
TrueScotsman bool `protobuf:"varint,8,opt,name=true_scotsman" json:"true_scotsman,omitempty"`
Score float32 `protobuf:"fixed32,9,opt,name=score" json:"score,omitempty"`
Key []uint64 `protobuf:"varint,5,rep,name=key" json:"key,omitempty"`
Nested *Nested `protobuf:"bytes,6,opt,name=nested" json:"nested,omitempty"`
Terrain map[string]*Nested `protobuf:"bytes,10,rep,name=terrain" json:"terrain,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
Proto2Field *testdata.SubDefaults `protobuf:"bytes,11,opt,name=proto2_field" json:"proto2_field,omitempty"`
Proto2Value map[string]*testdata.SubDefaults `protobuf:"bytes,13,rep,name=proto2_value" json:"proto2_value,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
}
func (m *Message) Reset() { *m = Message{} }
func (m *Message) String() string { return proto.CompactTextString(m) }
func (*Message) ProtoMessage() {}
func (m *Message) GetNested() *Nested {
if m != nil {
return m.Nested
}
return nil
}
func (m *Message) GetTerrain() map[string]*Nested {
if m != nil {
return m.Terrain
}
return nil
}
func (m *Message) GetProto2Field() *testdata.SubDefaults {
if m != nil {
return m.Proto2Field
}
return nil
}
func (m *Message) GetProto2Value() map[string]*testdata.SubDefaults {
if m != nil {
return m.Proto2Value
}
return nil
}
type Nested struct {
Bunny string `protobuf:"bytes,1,opt,name=bunny" json:"bunny,omitempty"`
}
func (m *Nested) Reset() { *m = Nested{} }
func (m *Nested) String() string { return proto.CompactTextString(m) }
func (*Nested) ProtoMessage() {}
type MessageWithMap struct {
ByteMapping map[bool][]byte `protobuf:"bytes,1,rep,name=byte_mapping" json:"byte_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
func (m *MessageWithMap) Reset() { *m = MessageWithMap{} }
func (m *MessageWithMap) String() string { return proto.CompactTextString(m) }
func (*MessageWithMap) ProtoMessage() {}
func (m *MessageWithMap) GetByteMapping() map[bool][]byte {
if m != nil {
return m.ByteMapping
}
return nil
}
func init() {
proto.RegisterEnum("proto3_proto.Message_Humour", Message_Humour_name, Message_Humour_value)
}
......@@ -31,6 +31,8 @@
syntax = "proto3";
import "testdata/test.proto";
package proto3_proto;
message Message {
......@@ -51,8 +53,16 @@ message Message {
repeated uint64 key = 5;
Nested nested = 6;
map<string, Nested> terrain = 10;
testdata.SubDefaults proto2_field = 11;
map<string, testdata.SubDefaults> proto2_value = 13;
}
message Nested {
string bunny = 1;
}
message MessageWithMap {
map<bool, bytes> byte_mapping = 1;
}
......@@ -37,11 +37,11 @@ import (
"bufio"
"bytes"
"encoding"
"errors"
"fmt"
"io"
"log"
"math"
"os"
"reflect"
"sort"
"strings"
......@@ -170,20 +170,12 @@ func writeName(w *textWriter, props *Properties) error {
return nil
}
var (
messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
)
// raw is the interface satisfied by RawMessage.
type raw interface {
Bytes() []byte
}
func writeStruct(w *textWriter, sv reflect.Value) error {
if sv.Type() == messageSetType {
return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
}
st := sv.Type()
sprops := GetProperties(st)
for i := 0; i < sv.NumField(); i++ {
......@@ -246,7 +238,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
}
if fv.Kind() == reflect.Map {
// Map fields are rendered as a repeated struct with key/value fields.
keys := fv.MapKeys() // TODO: should we sort these for deterministic output?
keys := fv.MapKeys()
sort.Sort(mapKeys(keys))
for _, key := range keys {
val := fv.MapIndex(key)
......@@ -283,20 +275,23 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
if err := w.WriteByte('\n'); err != nil {
return err
}
// value
if _, err := w.WriteString("value:"); err != nil {
return err
}
if !w.compact {
if err := w.WriteByte(' '); err != nil {
// 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 := writeAny(w, val, props.mvalprop); err != nil {
return err
}
if err := w.WriteByte('\n'); err != nil {
return err
}
}
if err := writeAny(w, val, props.mvalprop); err != nil {
return err
}
if err := w.WriteByte('\n'); err != nil {
return err
}
// close struct
w.unindent()
......@@ -315,26 +310,34 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
}
if fv.Kind() != reflect.Ptr && fv.Kind() != reflect.Slice {
// proto3 non-repeated scalar field; skip if zero value
switch fv.Kind() {
case reflect.Bool:
if !fv.Bool() {
continue
}
case reflect.Int32, reflect.Int64:
if fv.Int() == 0 {
continue
}
case reflect.Uint32, reflect.Uint64:
if fv.Uint() == 0 {
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
}
case reflect.Float32, reflect.Float64:
if fv.Float() == 0 {
continue
}
case reflect.String:
if fv.String() == "" {
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()
}
}
}
......@@ -514,44 +517,6 @@ func writeString(w *textWriter, s string) error {
return w.WriteByte('"')
}
func writeMessageSet(w *textWriter, ms *MessageSet) error {
for _, item := range ms.Item {
id := *item.TypeId
if msd, ok := messageSetMap[id]; ok {
// Known message set type.
if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
return err
}
w.indent()
pb := reflect.New(msd.t.Elem())
if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
return err
}
} else {
if err := writeStruct(w, pb.Elem()); err != nil {
return err
}
}
} else {
// Unknown type.
if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
return err
}
w.indent()
if err := writeUnknownStruct(w, item.Message); err != nil {
return err
}
}
w.unindent()
if _, err := w.Write(gtNewline); err != nil {
return err
}
}
return nil
}
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
if !w.compact {
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
......@@ -666,10 +631,7 @@ func writeExtensions(w *textWriter, pv reflect.Value) error {
pb, err := GetExtension(ep, desc)
if err != nil {
if _, err := fmt.Fprintln(os.Stderr, "proto: failed getting extension: ", err); err != nil {
return err
}
continue
return fmt.Errorf("failed getting extension: %v", err)
}
// Repeated extensions will appear as a slice.
......
......@@ -119,6 +119,14 @@ func isWhitespace(c byte) bool {
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] == '#') {
......@@ -174,7 +182,7 @@ func (p *textParser) advance() {
}
unq, err := unquoteC(p.s[1:i], rune(p.s[0]))
if err != nil {
p.errorf("invalid quoted string %v", p.s[0:i+1])
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)]
......@@ -333,13 +341,13 @@ func (p *textParser) next() *token {
p.advance()
if p.done {
p.cur.value = ""
} else if len(p.cur.value) > 0 && p.cur.value[0] == '"' {
} 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 || p.s[0] != '"' {
if p.done || !isQuote(p.s[0]) {
break
}
p.advance()
......@@ -385,8 +393,7 @@ func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSet
}
// Returns the index in the struct for the named field, as well as the parsed tag properties.
func structFieldByName(st reflect.Type, name string) (int, *Properties, bool) {
sprops := GetProperties(st)
func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) {
i, ok := sprops.decoderOrigNames[name]
if ok {
return i, sprops.Prop[i], true
......@@ -438,7 +445,8 @@ func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseEr
func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
st := sv.Type()
reqCount := GetProperties(st).reqCount
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
......@@ -520,99 +528,113 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
sl = reflect.Append(sl, ext)
SetExtension(ep, desc, sl.Interface())
}
} else {
// This is a normal, non-extension field.
name := tok.value
fi, props, ok := structFieldByName(st, name)
if !ok {
return p.errorf("unknown field name %q in %v", name, st)
if err := p.consumeOptionalSeparator(); err != nil {
return err
}
continue
}
dst := sv.Field(fi)
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 >
// Technically the "key" and "value" could come in any order,
// but in practice they won't.
tok := p.next()
var terminator string
switch tok.value {
case "<":
terminator = ">"
case "{":
terminator = "}"
default:
return p.errorf("expected '{' or '<', found %q", tok.value)
}
if err := p.consumeToken("key"); err != nil {
return err
}
if err := p.consumeToken(":"); err != nil {
return err
}
if err := p.readAny(key, props.mkeyprop); err != nil {
return err
}
if err := p.consumeToken("value"); err != nil {
return err
}
if err := p.consumeToken(":"); err != nil {
return err
}
if err := p.readAny(val, props.mvalprop); err != nil {
return err
}
if err := p.consumeToken(terminator); err != nil {
return err
}
// 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)
sv.Field(oop.Field).Set(nv)
}
if !dst.IsValid() {
return p.errorf("unknown field name %q in %v", name, st)
}
dst.SetMapIndex(key, val)
continue
if dst.Kind() == reflect.Map {
// Consume any colon.
if err := p.checkForColon(props, dst.Type()); err != nil {
return err
}
// 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)
// Construct the map if it doesn't already exist.
if dst.IsNil() {
dst.Set(reflect.MakeMap(dst.Type()))
}
if err := p.checkForColon(props, st.Field(fi).Type); err != nil {
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 >
// Technically the "key" and "value" could come in any order,
// but in practice they won't.
tok := p.next()
var terminator string
switch tok.value {
case "<":
terminator = ">"
case "{":
terminator = "}"
default:
return p.errorf("expected '{' or '<', found %q", tok.value)
}
if err := p.consumeToken("key"); 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
} else if props.Required {
reqCount--
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
}
if err := p.consumeToken("value"); err != nil {
return err
}
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
}
if err := p.consumeToken(terminator); err != nil {
return err
}
dst.SetMapIndex(key, val)
continue
}
// For backward compatibility, permit a semicolon or comma after a field.
tok = p.next()
if tok.err != nil {
return tok.err
// 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
} else if props.Required {
reqCount--
}
if tok.value != ";" && tok.value != "," {
p.back()
if err := p.consumeOptionalSeparator(); err != nil {
return err
}
}
if reqCount > 0 {
......@@ -621,6 +643,19 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
return reqFieldErr
}
// 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 {
......@@ -645,18 +680,32 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
fv.Set(reflect.ValueOf(bytes))
return nil
}
// Repeated field. May already exist.
flen := fv.Len()
if flen == fv.Cap() {
nav := reflect.MakeSlice(at, flen, 2*flen+1)
reflect.Copy(nav, fv)
fv.Set(nav)
// 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
}
fv.SetLen(flen + 1)
// Read one.
// One value of the repeated field.
p.back()
return p.readAny(fv.Index(flen), props)
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem()))
return p.readAny(fv.Index(fv.Len()-1), props)
case reflect.Bool:
// Either "true", "false", 1 or 0.
switch tok.value {
......
......@@ -10,8 +10,11 @@ Status:
* The client work has just started but shares a lot of code
is coming along much quicker.
Docs are at https://godoc.org/github.com/bradfitz/http2
Docs are at https://godoc.org/golang.org/x/net/http2
Demo test server at https://http2.golang.org/
Help & bug reports welcome.
Help & bug reports welcome!
Contributing: https://golang.org/doc/contribute.html
Bugs: https://github.com/golang/go/issues/new?title=x/net/http2:+
......@@ -19,8 +19,9 @@ type buffer struct {
}
var (
errReadEmpty = errors.New("read from empty buffer")
errWriteFull = errors.New("write on full buffer")
errReadEmpty = errors.New("read from empty buffer")
errWriteClosed = errors.New("write on closed buffer")
errWriteFull = errors.New("write on full buffer")
)
// Read copies bytes from the buffer into p.
......@@ -45,7 +46,7 @@ func (b *buffer) Len() int {
// It is an error to write more data than the buffer can hold.
func (b *buffer) Write(p []byte) (n int, err error) {
if b.closed {
return 0, errors.New("closed")
return 0, errWriteClosed
}
// Slide existing data to beginning.
......
......@@ -85,8 +85,8 @@ const (
// Continuation Frame
FlagContinuationEndHeaders Flags = 0x4
FlagPushPromiseEndHeaders = 0x4
FlagPushPromisePadded = 0x8
FlagPushPromiseEndHeaders Flags = 0x4
FlagPushPromisePadded Flags = 0x8
)
var flagName = map[FrameType]map[Flags]string{
......
......@@ -14,16 +14,20 @@ import (
"bytes"
"errors"
"fmt"
"os"
"runtime"
"strconv"
"sync"
)
var DebugGoroutines = false
var DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
type goroutineLock uint64
func newGoroutineLock() goroutineLock {
if !DebugGoroutines {
return 0
}
return goroutineLock(curGoroutineID())
}
......
......@@ -31,7 +31,7 @@ import (
"camlistore.org/pkg/googlestorage"
"camlistore.org/pkg/singleflight"
"github.com/bradfitz/http2"
"golang.org/x/net/http2"
)
var (
......@@ -51,7 +51,7 @@ func homeOldHTTP(w http.ResponseWriter, r *http.Request) {
<li>Use Firefox Nightly or go to <b>about:config</b> and enable "network.http.spdy.enabled.http2draft"</li>
<li>Use Google Chrome Canary and/or go to <b>chrome://flags/#enable-spdy4</b> to <i>Enable SPDY/4</i> (Chrome's name for HTTP/2)</li>
</ul>
<p>See code & instructions for connecting at <a href="https://github.com/bradfitz/http2">https://github.com/bradfitz/http2</a>.</p>
<p>See code & instructions for connecting at <a href="https://github.com/golang/net/tree/master/http2">https://github.com/golang/net/tree/master/http2</a>.</p>
</body></html>`)
}
......@@ -73,12 +73,12 @@ href="https://http2.github.io/">HTTP/2</a> demo & interop server.</p>
<p>This server exists for others in the HTTP/2 community to test their HTTP/2 client implementations and point out flaws in our server.</p>
<p> The code is currently at <a
href="https://github.com/bradfitz/http2">github.com/bradfitz/http2</a>
href="https://golang.org/x/net/http2">github.com/bradfitz/http2</a>
but will move to the Go standard library at some point in the future
(enabled by default, without users needing to change their code).</p>
<p>Contact info: <i>bradfitz@golang.org</i>, or <a
href="https://github.com/bradfitz/http2/issues">file a bug</a>.</p>
href="https://golang.org/x/net/http2/issues">file a bug</a>.</p>
<h2>Handlers for testing</h2>
<ul>
......@@ -287,7 +287,7 @@ func newGopherTilesHandler() http.Handler {
return
}
}
io.WriteString(w, "<html><body>")
io.WriteString(w, "<html><body onload='showtimes()'>")
fmt.Fprintf(w, "A grid of %d tiled images is below. Compare:<p>", xt*yt)
for _, ms := range []int{0, 30, 200, 1000} {
d := time.Duration(ms) * nanosPerMilli
......@@ -305,7 +305,16 @@ func newGopherTilesHandler() http.Handler {
}
io.WriteString(w, "<br/>\n")
}
io.WriteString(w, "<hr><a href='/'>&lt;&lt Back to Go HTTP/2 demo server</a></body></html>")
io.WriteString(w, `<p><div id='loadtimes'></div></p>
<script>
function showtimes() {
var times = 'Times from connection start:<br>'
times += 'DOM loaded: ' + (window.performance.timing.domContentLoadedEventEnd - window.performance.timing.connectStart) + 'ms<br>'
times += 'DOM complete (images loaded): ' + (window.performance.timing.domComplete - window.performance.timing.connectStart) + 'ms<br>'
document.getElementById('loadtimes').innerHTML = times
}
</script>
<hr><a href='/'>&lt;&lt Back to Go HTTP/2 demo server</a></body></html>`)
})
}
......
......@@ -20,8 +20,9 @@ import (
"strings"
"time"
"code.google.com/p/goauth2/oauth"
compute "code.google.com/p/google-api-go-client/compute/v1"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
compute "google.golang.org/api/compute/v1"
)
var (
......@@ -44,19 +45,18 @@ func readFile(v string) string {
return strings.TrimSpace(string(slurp))
}
var config = &oauth.Config{
var config = &oauth2.Config{
// The client-id and secret should be for an "Installed Application" when using
// the CLI. Later we'll use a web application with a callback.
ClientId: readFile("client-id.dat"),
ClientID: readFile("client-id.dat"),
ClientSecret: readFile("client-secret.dat"),
Scope: strings.Join([]string{
Endpoint: google.Endpoint,
Scopes: []string{
compute.DevstorageFull_controlScope,
compute.ComputeScope,
"https://www.googleapis.com/auth/sqlservice",
"https://www.googleapis.com/auth/sqlservice.admin",
}, " "),
AuthURL: "https://accounts.google.com/o/oauth2/auth",
TokenURL: "https://accounts.google.com/o/oauth2/token",
},
RedirectURL: "urn:ietf:wg:oauth:2.0:oob",
}
......@@ -88,31 +88,32 @@ func main() {
prefix := "https://www.googleapis.com/compute/v1/projects/" + *proj
machType := prefix + "/zones/" + *zone + "/machineTypes/" + *mach
tr := &oauth.Transport{
Config: config,
}
tokenCache := oauth.CacheFile("token.dat")
token, err := tokenCache.Token()
const tokenFileName = "token.dat"
tokenFile := tokenCacheFile(tokenFileName)
tokenSource := oauth2.ReuseTokenSource(nil, tokenFile)
token, err := tokenSource.Token()
if err != nil {
if *writeObject != "" {
log.Fatalf("Can't use --write_object without a valid token.dat file already cached.")
}
log.Printf("Error getting token from %s: %v", string(tokenCache), err)
log.Printf("Error getting token from %s: %v", tokenFileName, err)
log.Printf("Get auth code from %v", config.AuthCodeURL("my-state"))
fmt.Print("\nEnter auth code: ")
sc := bufio.NewScanner(os.Stdin)
sc.Scan()
authCode := strings.TrimSpace(sc.Text())
token, err = tr.Exchange(authCode)
token, err = config.Exchange(oauth2.NoContext, authCode)
if err != nil {
log.Fatalf("Error exchanging auth code for a token: %v", err)
}
tokenCache.PutToken(token)
if err := tokenFile.WriteToken(token); err != nil {
log.Fatalf("Error writing to %s: %v", tokenFileName, err)
}
tokenSource = oauth2.ReuseTokenSource(token, nil)
}
tr.Token = token
oauthClient := &http.Client{Transport: tr}
oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
if *writeObject != "" {
writeCloudStorageObject(oauthClient)
return
......@@ -277,3 +278,25 @@ func writeCloudStorageObject(httpClient *http.Client) {
log.Printf("Success.")
os.Exit(0)
}
type tokenCacheFile string
func (f tokenCacheFile) Token() (*oauth2.Token, error) {
slurp, err := ioutil.ReadFile(string(f))
if err != nil {
return nil, err
}
t := new(oauth2.Token)
if err := json.Unmarshal(slurp, t); err != nil {
return nil, err
}
return t, nil
}
func (f tokenCacheFile) WriteToken(t *oauth2.Token) error {
jt, err := json.Marshal(t)
if err != nil {
return err
}
return ioutil.WriteFile(string(f), jt, 0600)
}
# h2i
**h2i** is an interactive HTTP/2 ("h2") console debugger. Miss the good ol'
days of telnetting to your HTTP/1.n servers? We're bringing you
back.
Features:
- send raw HTTP/2 frames
- PING
- SETTINGS
- HEADERS
- etc
- type in HTTP/1.n and have it auto-HPACK/frame-ify it for HTTP/2
- pretty print all received HTTP/2 frames from the peer (including HPACK decoding)
- tab completion of commands, options
Not yet features, but soon:
- unnecessary CONTINUATION frames on short boundaries, to test peer implementations
- request bodies (DATA frames)
- send invalid frames for testing server implementations (supported by underlying Framer)
Later:
- act like a server
## Installation
```
$ go get golang.org/x/net/http2/h2i
$ h2i <host>
```
## Demo
```
$ h2i
Usage: h2i <hostname>
-insecure
Whether to skip TLS cert validation
-nextproto string
Comma-separated list of NPN/ALPN protocol names to negotiate. (default "h2,h2-14")
$ h2i google.com
Connecting to google.com:443 ...
Connected to 74.125.224.41:443
Negotiated protocol "h2-14"
[FrameHeader SETTINGS len=18]
[MAX_CONCURRENT_STREAMS = 100]
[INITIAL_WINDOW_SIZE = 1048576]
[MAX_FRAME_SIZE = 16384]
[FrameHeader WINDOW_UPDATE len=4]
Window-Increment = 983041
h2i> PING h2iSayHI
[FrameHeader PING flags=ACK len=8]
Data = "h2iSayHI"
h2i> headers
(as HTTP/1.1)> GET / HTTP/1.1
(as HTTP/1.1)> Host: ip.appspot.com
(as HTTP/1.1)> User-Agent: h2i/brad-n-blake
(as HTTP/1.1)>
Opening Stream-ID 1:
:authority = ip.appspot.com
:method = GET
:path = /
:scheme = https
user-agent = h2i/brad-n-blake
[FrameHeader HEADERS flags=END_HEADERS stream=1 len=77]
:status = "200"
alternate-protocol = "443:quic,p=1"
content-length = "15"
content-type = "text/html"
date = "Fri, 01 May 2015 23:06:56 GMT"
server = "Google Frontend"
[FrameHeader DATA flags=END_STREAM stream=1 len=15]
"173.164.155.78\n"
[FrameHeader PING len=8]
Data = "\x00\x00\x00\x00\x00\x00\x00\x00"
h2i> ping
[FrameHeader PING flags=ACK len=8]
Data = "h2i_ping"
h2i> ping
[FrameHeader PING flags=ACK len=8]
Data = "h2i_ping"
h2i> ping
[FrameHeader GOAWAY len=22]
Last-Stream-ID = 1; Error-Code = PROTOCOL_ERROR (1)
ReadFrame: EOF
```
## Status
Quick few hour hack. So much yet to do. Feel free to file issues for
bugs or wishlist items, but [@bmizerany](https://github.com/bmizerany/)
and I aren't yet accepting pull requests until things settle down.
......@@ -13,7 +13,7 @@
// ConfigureServer. That ConfigureServer call will likely be automatic
// or available via an empty import in the future.
//
// This package currently targets draft-14. See http://http2.github.io/
// See http://http2.github.io/
package http2
import (
......
......@@ -55,7 +55,7 @@ import (
"sync"
"time"
"github.com/bradfitz/http2/hpack"
"golang.org/x/net/http2/hpack"
)
const (
......@@ -631,6 +631,9 @@ func (sc *serverConn) serve() {
case wm := <-sc.wantWriteFrameCh:
sc.writeFrame(wm)
case <-sc.wroteFrameCh:
if sc.writingFrame != true {
panic("internal error: expected to be already writing a frame")
}
sc.writingFrame = false
sc.scheduleFrameWrite()
case fg, ok := <-sc.readFrameCh:
......@@ -752,6 +755,7 @@ func (sc *serverConn) startFrameWrite(wm frameWriteMsg) {
if sc.writingFrame {
panic("internal error: can only be writing one frame at a time")
}
sc.writingFrame = true
st := wm.stream
if st != nil {
......@@ -768,7 +772,6 @@ func (sc *serverConn) startFrameWrite(wm frameWriteMsg) {
}
}
sc.writingFrame = true
sc.needsFrameFlush = true
if endsStream(wm.write) {
if st == nil {
......
......@@ -19,7 +19,7 @@ import (
"strings"
"sync"
"github.com/bradfitz/http2/hpack"
"golang.org/x/net/http2/hpack"
)
type Transport struct {
......@@ -186,7 +186,7 @@ func (t *Transport) newClientConn(host, port, key string) (*clientConn, error) {
NextProtos: []string{NextProtoTLS},
InsecureSkipVerify: t.InsecureTLSDial,
}
tconn, err := tls.Dial("tcp", host+":"+port, cfg)
tconn, err := tls.Dial("tcp", net.JoinHostPort(host, port), cfg)
if err != nil {
return nil, err
}
......
......@@ -13,7 +13,7 @@ import (
"net/http"
"time"
"github.com/bradfitz/http2/hpack"
"golang.org/x/net/http2/hpack"
)
// writeFramer is implemented by any type that is used to write frames.
......
language: go
before_install:
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover
install:
- mkdir -p "$GOPATH/src/google.golang.org"
- mv "$TRAVIS_BUILD_DIR" "$GOPATH/src/google.golang.org/grpc"
script:
- make test testrace
- make coverage
# Authentication
As outlined <a href="https://github.com/grpc/grpc/blob/master/doc/grpc-auth-support.md">here</a> gRPC supports a number of different mechanisms for asserting identity between an client and server. We'll present some code-samples here demonstrating how to provide TLS support encryption and identity assertions as well as passing OAuth2 tokens to services that support it.
As outlined in the [gRPC authentication guide](http://www.grpc.io/docs/guides/auth.html) there are a number of different mechanisms for asserting identity between an client and server. We'll present some code-samples here demonstrating how to provide TLS support encryption and identity assertions as well as passing OAuth2 tokens to services that support it.
# Enabling TLS on a gRPC client
......
......@@ -45,3 +45,6 @@ testrace: testdeps
clean:
go clean google.golang.org/grpc/...
coverage: testdeps
./coverage.sh --coveralls
......@@ -2,12 +2,12 @@
[![Build Status](https://travis-ci.org/grpc/grpc-go.svg)](https://travis-ci.org/grpc/grpc-go) [![GoDoc](https://godoc.org/google.golang.org/grpc?status.svg)](https://godoc.org/google.golang.org/grpc)
The Go implementation of [gRPC](https://github.com/grpc/grpc)
The Go implementation of [gRPC](http://www.grpc.io/): A high performance, open source, general RPC framework that puts mobile and HTTP/2 first. For more information see the [gRPC Quick Start](http://www.grpc.io/docs/) guide.
Installation
------------
To install this package, you need to install Go 1.4 and setup your Go workspace on your computer. The simplest way to install the library is to run:
To install this package, you need to install Go 1.4 or above and setup your Go workspace on your computer. The simplest way to install the library is to run:
```
$ go get google.golang.org/grpc
......@@ -18,11 +18,15 @@ Prerequisites
This requires Go 1.4 or above.
Constraints
-----------
The grpc package should only depend on standard Go packages and a small number of exceptions. If your contribution introduces new dependencies which are NOT in the [list](http://godoc.org/google.golang.org/grpc?imports), you need a discussion with gRPC-Go authors and consultants.
Documentation
-------------
You can find more detailed documentation and examples in the [examples directory](examples/).
See [API documentation](https://godoc.org/google.golang.org/grpc) for package and API descriptions and find examples in the [examples directory](examples/).
Status
------
Alpha - ready for early adopters.
Beta release
......@@ -92,13 +92,6 @@ func closeLoopUnary() {
func closeLoopStream() {
s, conn, tc := buildConnection()
stream, err := tc.StreamingCall(context.Background())
if err != nil {
grpclog.Fatalf("%v.StreamingCall(_) = _, %v", tc, err)
}
for i := 0; i < 100; i++ {
streamCaller(tc, stream)
}
ch := make(chan int, *maxConcurrentRPCs*4)
var (
mu sync.Mutex
......@@ -108,7 +101,15 @@ func closeLoopStream() {
// Distribute RPCs over maxConcurrentCalls workers.
for i := 0; i < *maxConcurrentRPCs; i++ {
go func() {
for _ = range ch {
stream, err := tc.StreamingCall(context.Background())
if err != nil {
grpclog.Fatalf("%v.StreamingCall(_) = _, %v", tc, err)
}
// Do some warm up.
for i := 0; i < 100; i++ {
streamCaller(tc, stream)
}
for range ch {
start := time.Now()
streamCaller(tc, stream)
elapse := time.Since(start)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment