Skip to content

Commit

Permalink
docs: path parameter unescaping
Browse files Browse the repository at this point in the history
  • Loading branch information
v3n committed Sep 10, 2021
1 parent f1ff145 commit 5f013c0
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 10 deletions.
4 changes: 4 additions & 0 deletions docs/docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ When a message is added which happens to conflict with another message (e.g. by

The gRPC-Gateway is a generator that generates a Go implementation of a JSON/HTTP-gRPC reverse proxy based on annotations in your proto file, while the [grpc-httpjson-transcoding](https://github.com/grpc-ecosystem/grpc-httpjson-transcoding) library doesn't require the generation step, it uses protobuf descriptors as config. It can be used as a component of an existing proxy. Google Cloud Endpoints and the gRPC-JSON transcoder filter in Envoy are using this.

<!-- TODO(v3): remove this note when default behavior matches Envoy/Cloud Endpoints -->
**Behavior differences:**
- By default, gRPC-Gateway does not escape path parameters in the same way. [This can be configured.](../mapping/customizing_your_gateway.md#Controlling-path-parameter-unescaping)

## What is the difference between the gRPC-Gateway and gRPC-web?

### Usage
Expand Down
24 changes: 24 additions & 0 deletions docs/docs/mapping/customizing_your_gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,30 @@ func handleStreamError(ctx context.Context, err error) *status.Status {

If no custom handler is provided, the default stream error handler will include any gRPC error attributes (code, message, detail messages), if the error being reported includes them. If the error does not have these attributes, a gRPC code of `Unknown` (2) is reported.

## Controlling path parameter unescaping

<!-- TODO(v3): Remove comments about default behavior -->

By default, gRPC-Gateway unescapes the entire URL path string attempting to route a request. This causes routing errors when the path parameter contains an illegal character such as `/`.

To replicate the behavior described in [google.api.http](https://github.com/googleapis/googleapis/blob/master/google/api/http.proto#L224), use [runtime.WithUnescapingMode()](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/runtime?tab=doc#WithUnescapingMode) to configure the unescaping behavior, as in the example below:

```go
mux := runtime.NewServeMux(
runtime.WithUnescapingMode(runtime.UnescapingModeAllExceptReserved),
)
```

For multi-segment parameters (e.g. `{id=**}`) [RFC 6570](https://tools.ietf.org/html/rfc6570) Reserved Expansion characters are left escaped and the gRPC API will need to unescape them.

To replicate the default V2 escaping behavior but also allow passing pct-encoded `/` characters, the ServeMux can be configured as in the example below:

```go
mux := runtime.NewServeMux(
runtime.WithUnescapingMode(runtime.UnescapingModeAllCharacters),
)
```

## Routing Error handler

To override the error behavior when `*runtime.ServeMux` was not able to serve the request due to routing issues, use the `runtime.WithRoutingErrorHandler` option.
Expand Down
2 changes: 1 addition & 1 deletion runtime/mux.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package runtime

import (
"errors"
"context"
"errors"
"fmt"
"net/http"
"net/textproto"
Expand Down
17 changes: 8 additions & 9 deletions runtime/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ func MustPattern(p Pattern, err error) Pattern {
return p
}

// MatchAndEscape examines components if it matches to the Pattern. If it matches,
// the function returns a mapping from field paths to their captured values while
// applying the provided unescaping mode, returning an error if the URL encoding
// is malformed. Otherwise, the function returns an error.
// MatchAndEscape examines components to determine if they match to a Pattern.
// MatchAndEscape will return an error if no Patterns matched or if a pattern
// matched but contained malformed escape sequences. If successful, the function
// returns a mapping from field paths to their captured values.
func (p Pattern) MatchAndEscape(components []string, verb string, unescapingMode UnescapingMode) (map[string]string, error) {
if p.verb != verb {
if p.verb != "" {
Expand Down Expand Up @@ -224,9 +224,10 @@ func (p Pattern) MatchAndEscape(components []string, verb string, unescapingMode
return bindings, nil
}

// Match examines components if it matches to the Pattern.
// If it matches, the function returns a mapping from field paths to their captured values.
// If otherwise, the function returns an error.
// MatchAndEscape examines components to determine if they match to a Pattern.
// It will never perform per-component unescaping (see: UnescapingModeLegacy).
// MatchAndEscape will return an error if no Patterns matched. If successful,
// the function returns a mapping from field paths to their captured values.
//
// Deprecated: Use MatchAndEscape.
func (p Pattern) Match(components []string, verb string) (map[string]string, error) {
Expand Down Expand Up @@ -286,7 +287,6 @@ func ishex(c byte) bool {
return false
}


func isRFC6570Reserved(c byte) bool {
switch c {
case '!', '#', '$', '&', '\'', '(', ')', '*',
Expand Down Expand Up @@ -381,4 +381,3 @@ func unescape(s string, mode UnescapingMode, multisegment bool) (string, error)

return t.String(), nil
}

0 comments on commit 5f013c0

Please sign in to comment.