luci: Index | Files | Directories

package prpc

import ""

Package prpc (provisional RPC) implements an RPC client over HTTP 1.x.

Like gRPC:

- services are defined in .proto files
- service implementation does not depend on pRPC.

Unlike gRPC:

- supports HTTP 1.x and AppEngine 1.x.
- does not support streams.


Type Server implements a pRPC server.

Example of usage:

Package discovery implements service discovery.

Compile service definitions

Use cproto tool to compile .proto files to .go files with gRPC and pRPC support. It runs protoc and does some additional postprocessing.

//go:generate cproto

Install cproto:

go install


## v1.1

v1.1 is small, backward-compatible amendment to the protocol to address a security issue. Since it is backward compatible, it does not introduce a formal protocol version header at this time.


- Requests/responses must use "application/json" media type instead of
  "application/prpc; encoding=json".
- Responses must include "X-Content-Type-Options: nosniff" HTTP header.

This enables CORB protection (which mitigates spectre) and disables content sniffing. For CORB, see

## v1.0

This section describes the pRPC protocol. It is based on HTTP 1.x and employs gRPC codes.

A pRPC server MUST handle HTTP POST requests at `/prpc/{service}/{method}` where service is a full service name including full package name. The handler must decode an input message from an HTTP request, call the service method implementation and encode the returned output message or error to the HTTP response.

pRPC protocol defines three protocol buffer encodings and media types.

- Binary: "application/prpc; encoding=binary" (default).
- JSON:   "application/prpc; encoding=json"   or "application/json"
  A response body MUST have `)]}'\n` prefix to prevent XSSI.
- Text:   "application/prpc; encoding=text"

A pRPC server MUST support Binary and SHOULD support JSON and Text.

Request headers:

- "X-Prpc-Timeout": specifies request timeout.
  A client MAY specify it.
  If a service hits the timeout, a server MUST respond with HTTP 503 and
  DeadlineExceed gRPC code.
  Value format: `\d+[HMSmun]` (regular expression), where
   - H - hour
   - M - minute
   - S - second
   - m - millisecond
   - u - microsecond
   - n - nanosecond
- "Content-Type": specifies input message encoding in the body.
  A client SHOULD specify it.
  If not present, a server MUST treat the input message as Binary.
- "Accept": specifies the output message encoding for the response.
  A client MAY specify it, a server MUST support it.
- Any other headers MUST be added to metadata.MD in the context that is
  passed to the service method implementation.
  - If a header name has "-Bin" suffix, the server must treat it as
    base64-encoded and trim the suffix.

Response headers:

- "X-Prpc-Grpc-Code": specifies the gRPC code.
  A server MUST specify it in all cases.
  - If it is present, the client MUST ignore the HTTP status code.
    - If OK, the client MUST return the output message
      decoded from the body.
    - Otherwise, the client MUST return a gRPC error with the
      code and message read from the response body.
  - If not present, the client MUST return a non-gRPC error
    with message read from the response body.
    A client MAY read a portion of the response body.
- "Content-Type": specifies the output message encoding.
  A server SHOULD specify it.
  If not specified, a client MUST treat it is as Binary.
- Any metadata returned by a service method implementation MUST go into
  http headers, unless metadata key starts with "X-Prpc-".

A server MUST always specify "X-Prpc-Grpc-Code". The server SHOULD specify HTTP status corresponding to the gRPC code.

If the "X-Prpc-Grpc-Code" response header value is not 0, the response body MUST contain a description of the error.

If a service/method is not found, the server MUST respond with Unimplemented gRPC code and SHOULD specify HTTP 501 status.


Package Files

accept.go auth.go client.go decoding.go doc.go encoding.go error.go format.go generate.go metadata.go options.go registrar.go server.go timeout.go


const (
    // HeaderGRPCCode is a name of the HTTP header that specifies the
    // gRPC code in the response.
    // A pRPC server must always specify it.
    HeaderGRPCCode = "X-Prpc-Grpc-Code"

    // HeaderTimeout is HTTP header used to set pRPC request timeout.
    // The single value should match regexp `\d+[HMSmun]`.
    HeaderTimeout = "X-Prpc-Grpc-Timeout"

    // DefaultMaxContentLength is the default maximum content length (in bytes)
    // for a Client. It is 32MiB.
    DefaultMaxContentLength = 32 * 1024 * 1024
const (
    // ContentTypePRPC is the formal MIME content type for pRPC messages.
    ContentTypePRPC = "application/prpc"
    // ContentTypeJSON is the JSON content type.
    ContentTypeJSON = "application/json"

    // JSONPBPrefix is prepended to a message in JSONPB format to avoid CSRF.
    JSONPBPrefix = ")]}'\n"


var (
    // DefaultUserAgent is default User-Agent HTTP header for pRPC requests.
    DefaultUserAgent = "pRPC Client 1.0"

    // ErrResponseTooBig is returned by Call when the Response's body size exceeds
    // the Client's soft limit, MaxContentLength.
    ErrResponseTooBig = errors.New("response too big")

func DecodeTimeout Uses

func DecodeTimeout(s string) (time.Duration, error)

DecodeTimeout decodes a gRPC/pRPC timeout header string into a time.Duration.

func EncodeTimeout Uses

func EncodeTimeout(t time.Duration) string

EncodeTimeout encodes a gRPC/pRPC timeout into a timeout header time.Duration.

This rounds the time.Duration to the smallest time unit that can represent it.

func RegisterDefaultAuth Uses

func RegisterDefaultAuth(a Authenticator)

RegisterDefaultAuth sets a default authenticator that is used unless Server.Authenticator is provided.

It is supposed to be used during init() time, to configure the default authentication method used by the program.

For example, see luci-go/appengine/gaeauth/server/prpc.go, that gets imported by LUCI GAE apps. It sets up authentication based on LUCI auth framework.

Panics if 'a' is nil or a default authenticator is already set.

func SetHeader Uses

func SetHeader(ctx context.Context, md metadata.MD) error

SetHeader sets the header metadata. When called multiple times, all the provided metadata will be merged.

If ctx is not a pRPC server context, then SetHeader calls grpc.SetHeader such that calling prpc.SetHeader works for both pRPC and gRPC.

type Authenticator Uses

type Authenticator interface {
    // Authenticate returns a context populated with authentication related
    // values.
    // If the request is authenticated, 'Authenticate' returns a derived context
    // that gets passed to the RPC handler.
    // If the request cannot be authenticated, 'Authenticate' returns nil context
    // and an error. A non-transient error triggers Unauthenticated grpc error,
    // a transient error triggers Internal grpc error. In both cases the error
    // message is set to err.Error().
    Authenticate(context.Context, *http.Request) (context.Context, error)

Authenticator authenticates incoming pRPC requests.

var (

    // NoAuthentication can be used in place of an Authenticator to explicitly
    // specify that your Server will skip authentication.
    // Use it with Server.Authenticator or RegisterDefaultAuth.
    NoAuthentication Authenticator = nullAuthenticator{}

func GetDefaultAuth Uses

func GetDefaultAuth() Authenticator

GetDefaultAuth returns the default authenticator set by RegisterDefaultAuth or nil if not registered.

type CallOption Uses

type CallOption struct {
    // contains filtered or unexported fields

CallOption mutates Options.

func ExpectedCode Uses

func ExpectedCode(codes *CallOption

ExpectedCode can be used to indicate that given non-OK codes may appear during normal successful call flow, and thus they must not be logged as erroneous.

Only affects local logging, nothing else.

func Header(md *metadata.MD) *CallOption

Header returns a CallOption that retrieves the header metadata. Can be used instead of with grpc.Header.

func Trailer Uses

func Trailer(md *metadata.MD) *CallOption

Trailer returns a CallOption that retrieves the trailer metadata. Can be used instead of grpc.Trailer.

type Client Uses

type Client struct {
    C   *http.Client // if nil, uses http.DefaultClient

    // ErrBodySize is the number of bytes to read from a HTTP response
    // with error status and include in the error.
    // If non-positive, defaults to 256.
    ErrBodySize int

    // MaxContentLength, if > 0, is the maximum content length, in bytes, that a
    // pRPC is willing to read from the server. If a larger content length is
    // present in the response, ErrResponseTooBig will be returned.
    // If <= 0, DefaultMaxContentLength will be used.
    MaxContentLength int

    Host    string   // host and optionally a port number of the target server.
    Options *Options // if nil, DefaultOptions() are used.
    // contains filtered or unexported fields

Client can make pRPC calls.

func (*Client) Call Uses

func (c *Client) Call(ctx context.Context, serviceName, methodName string, in, out proto.Message, opts ...grpc.CallOption) error

Call makes an RPC. Retries on transient errors according to retry options. Logs HTTP errors.

opts must be created by this package. Calling from multiple goroutines concurrently is safe, unless Client is mutated. Called from generated code.

If there is a Deadline applied to the Context, it will be forwarded to the server using the HeaderTimeout header.

func (*Client) CallRaw Uses

func (c *Client) CallRaw(ctx context.Context, serviceName, methodName string, in []byte, inf, outf Format,
    opts ...grpc.CallOption) ([]byte, error)

CallRaw makes an RPC, sending and returning the raw data without unmarshalling it. Retries on transient errors according to retry options. Logs HTTP errors. Trims JSONPBPrefix.

opts must be created by this package. Calling from multiple goroutines concurrently is safe, unless Client is mutated. Called from generated code.

If there is a Deadline applied to the Context, it will be forwarded to the server using the HeaderTimeout header.

type Format Uses

type Format int

Format is the pRPC protobuf wire format specification.

const (
    // FormatBinary indicates that a message is encoded as a raw binary protobuf.
    FormatBinary Format = iota
    // FormatJSONPB indicates that a message is encoded as a JSON-serialized
    // protobuf.
    // FormatText indicates that a message is encoded as a text protobuf.

(Ordered by preference).

func FormatFromContentType Uses

func FormatFromContentType(v string) (Format, error)

FormatFromContentType converts Content-Type header value from a request to a format. Can return only FormatBinary, FormatJSONPB or FormatText. In case of an error, format is undefined.

func FormatFromEncoding Uses

func FormatFromEncoding(v string) (Format, error)

FormatFromEncoding converts a media type encoding parameter into a pRPC Format. Can return only FormatBinary, FormatJSONPB or FormatText. In case of an error, format is undefined.

func FormatFromMediaType Uses

func FormatFromMediaType(mt string, params map[string]string) (Format, error)

FormatFromMediaType converts a media type ContentType and its parameters into a pRPC Format. Can return only FormatBinary, FormatJSONPB or FormatText. In case of an error, format is undefined.

func (Format) MediaType Uses

func (f Format) MediaType() string

MediaType returns a full media type for f.

type Options Uses

type Options struct {
    Retry retry.Factory // RPC retrial.

    // UserAgent is the value of User-Agent HTTP header.
    // If empty, DefaultUserAgent is used.
    UserAgent string
    Insecure  bool // if true, use HTTP instead of HTTPS.

    // PerRPCTimeout, if > 0, is a timeout that is applied to each RPC. If the
    // client Context has a shorter deadline, this timeout will not be applied.
    // Otherwise, if this timeout is hit, the RPC round will be considered
    // transient.
    PerRPCTimeout time.Duration
    // contains filtered or unexported fields

Options controls how RPC requests are sent.

func DefaultOptions Uses

func DefaultOptions() *Options

DefaultOptions are used if no options are specified in Client.

type Registrar Uses

type Registrar interface {
    // RegisterService registers a service and its implementation.
    // Called from the generated code.
    RegisterService(desc *grpc.ServiceDesc, impl interface{})

Registrar can register a service. It is implemented by *grpc.Server and used instead of grpc.Server in the code generated by cproto.

type Server Uses

type Server struct {
    // Authenticator, if not nil, specifies how to authenticate requests.
    // If nil, the default authenticator set by RegisterDefaultAuth will be used.
    // If the default authenticator is also nil, all request handlers will panic.
    // If you want to disable the authentication (e.g for tests), explicitly set
    // Authenticator to NoAuthentication.
    Authenticator Authenticator

    // AccessControl, if not nil, is a callback that is invoked per request to
    // determine if permissive access control headers should be added to the
    // response.
    // This callback includes the request Context and the origin header supplied
    // by the client. If nil, or if it returns false, no headers will be written.
    // Otherwise, access control headers for the specified origin will be
    // included in the response.
    AccessControl func(c context.Context, origin string) bool

    // UnaryServerInterceptor provides a hook to intercept the execution of
    // a unary RPC on the server. It is the responsibility of the interceptor to
    // invoke handler to complete the RPC.
    UnaryServerInterceptor grpc.UnaryServerInterceptor
    // contains filtered or unexported fields

Server is a pRPC server to serve RPC requests. Zero value is valid.

func (*Server) InstallHandlers Uses

func (s *Server) InstallHandlers(r *router.Router, base router.MiddlewareChain)

InstallHandlers installs HTTP handlers at /prpc/:service/:method.

See for pRPC protocol.

The authenticator in 'base' is always replaced by pRPC specific one. For more details about the authentication see Server.Authenticator doc.

func (*Server) RegisterService Uses

func (s *Server) RegisterService(desc *grpc.ServiceDesc, impl interface{})

RegisterService registers a service implementation. Called from the generated code.

desc must contain description of the service, its message types and all transitive dependencies.

Panics if a service of the same name is already registered.

func (*Server) ServiceNames Uses

func (s *Server) ServiceNames() []string

ServiceNames returns a sorted list of full names of all registered services.



Package prpc imports 29 packages (graph) and is imported by 113 packages. Updated 2019-10-21. Refresh now. Tools for package owners.