Skip to content

Commit

Permalink
Merge pull request #401 from ipfs/release-v0.10.2
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Jun 29, 2023
2 parents 198f9bc + 2d3edc5 commit 61f2939
Show file tree
Hide file tree
Showing 25 changed files with 1,360 additions and 1,029 deletions.
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,45 @@ The following emojis are used to highlight certain changes:

## [Unreleased]

### Added

### Changed

### Removed

### Fixed

### Security

## [0.10.2] - 2023-06-29

### Fixed

- Gateway: include CORS on subdomain redirects.
- Gateway: ensure 'X-Ipfs-Root' header is valid.

## [0.10.1] - 2023-06-19

### Added

None.

### Changed

None.

### Removed

None.

### Fixed

- Allow CAR requests with a path when `DeserializedResponses` is `false`.

### Security

None.

## [0.10.0] - 2023-06-09

### Added
Expand Down
39 changes: 25 additions & 14 deletions gateway/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,35 @@ import (
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestErrRetryAfterIs(t *testing.T) {
t.Parallel()
var err error

err = NewErrorRetryAfter(errors.New("test"), 10*time.Second)
assert.True(t, errors.Is(err, &ErrorRetryAfter{}), "pointer to error must be error")
require.True(t, errors.Is(err, &ErrorRetryAfter{}), "pointer to error must be error")

err = fmt.Errorf("wrapped: %w", err)
assert.True(t, errors.Is(err, &ErrorRetryAfter{}), "wrapped pointer to error must be error")
require.True(t, errors.Is(err, &ErrorRetryAfter{}), "wrapped pointer to error must be error")
}

func TestErrRetryAfterAs(t *testing.T) {
t.Parallel()

var (
err error
errRA *ErrorRetryAfter
)

err = NewErrorRetryAfter(errors.New("test"), 25*time.Second)
assert.True(t, errors.As(err, &errRA), "pointer to error must be error")
assert.EqualValues(t, errRA.RetryAfter, 25*time.Second)
require.True(t, errors.As(err, &errRA), "pointer to error must be error")
require.EqualValues(t, errRA.RetryAfter, 25*time.Second)

err = fmt.Errorf("wrapped: %w", err)
assert.True(t, errors.As(err, &errRA), "wrapped pointer to error must be error")
assert.EqualValues(t, errRA.RetryAfter, 25*time.Second)
require.True(t, errors.As(err, &errRA), "wrapped pointer to error must be error")
require.EqualValues(t, errRA.RetryAfter, 25*time.Second)
}

func TestWebError(t *testing.T) {
Expand All @@ -43,37 +46,45 @@ func TestWebError(t *testing.T) {
config := &Config{Headers: map[string][]string{}}

t.Run("429 Too Many Requests", func(t *testing.T) {
t.Parallel()

err := fmt.Errorf("wrapped for testing: %w", NewErrorRetryAfter(ErrTooManyRequests, 0))
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/blah", nil)
webError(w, r, config, err, http.StatusInternalServerError)
assert.Equal(t, http.StatusTooManyRequests, w.Result().StatusCode)
assert.Zero(t, len(w.Result().Header.Values("Retry-After")))
require.Equal(t, http.StatusTooManyRequests, w.Result().StatusCode)
require.Zero(t, len(w.Result().Header.Values("Retry-After")))
})

t.Run("429 Too Many Requests with Retry-After header", func(t *testing.T) {
t.Parallel()

err := NewErrorRetryAfter(ErrTooManyRequests, 25*time.Second)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/blah", nil)
webError(w, r, config, err, http.StatusInternalServerError)
assert.Equal(t, http.StatusTooManyRequests, w.Result().StatusCode)
assert.Equal(t, "25", w.Result().Header.Get("Retry-After"))
require.Equal(t, http.StatusTooManyRequests, w.Result().StatusCode)
require.Equal(t, "25", w.Result().Header.Get("Retry-After"))
})

t.Run("503 Service Unavailable with Retry-After header", func(t *testing.T) {
t.Parallel()

err := NewErrorRetryAfter(ErrServiceUnavailable, 50*time.Second)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/blah", nil)
webError(w, r, config, err, http.StatusInternalServerError)
assert.Equal(t, http.StatusServiceUnavailable, w.Result().StatusCode)
assert.Equal(t, "50", w.Result().Header.Get("Retry-After"))
require.Equal(t, http.StatusServiceUnavailable, w.Result().StatusCode)
require.Equal(t, "50", w.Result().Header.Get("Retry-After"))
})

t.Run("ErrorStatusCode propagates HTTP Status Code", func(t *testing.T) {
t.Parallel()

err := NewErrorStatusCodeFromStatus(http.StatusTeapot)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/blah", nil)
webError(w, r, config, err, http.StatusInternalServerError)
assert.Equal(t, http.StatusTeapot, w.Result().StatusCode)
require.Equal(t, http.StatusTeapot, w.Result().StatusCode)
})
}
22 changes: 14 additions & 8 deletions gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,20 +320,22 @@ func cleanHeaderSet(headers []string) []string {
return result
}

// AddAccessControlHeaders adds default HTTP headers used for controlling
// cross-origin requests. This function adds several values to the
// [Access-Control-Allow-Headers] and [Access-Control-Expose-Headers] entries.
// AddAccessControlHeaders ensures safe default HTTP headers are used for
// controlling cross-origin requests. This function adds several values to the
// [Access-Control-Allow-Headers] and [Access-Control-Expose-Headers] entries
// to be exposed on GET and OPTIONS responses, including [CORS Preflight].
//
// If the Access-Control-Allow-Origin entry is missing a value of '*' is
// If the Access-Control-Allow-Origin entry is missing, a default value of '*' is
// added, indicating that browsers should allow requesting code from any
// origin to access the resource.
//
// If the Access-Control-Allow-Methods entry is missing a value of 'GET' is
// added, indicating that browsers may use the GET method when issuing cross
// If the Access-Control-Allow-Methods entry is missing a value, 'GET, HEAD,
// OPTIONS' is added, indicating that browsers may use them when issuing cross
// origin requests.
//
// [Access-Control-Allow-Headers]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
// [Access-Control-Expose-Headers]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
// [CORS Preflight]: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
func AddAccessControlHeaders(headers map[string][]string) {
// Hard-coded headers.
const ACAHeadersName = "Access-Control-Allow-Headers"
Expand All @@ -346,8 +348,12 @@ func AddAccessControlHeaders(headers map[string][]string) {
headers[ACAOriginName] = []string{"*"}
}
if _, ok := headers[ACAMethodsName]; !ok {
// Default to GET
headers[ACAMethodsName] = []string{http.MethodGet}
// Default to GET, HEAD, OPTIONS
headers[ACAMethodsName] = []string{
http.MethodGet,
http.MethodHead,
http.MethodOptions,
}
}

headers[ACAHeadersName] = cleanHeaderSet(
Expand Down
Loading

0 comments on commit 61f2939

Please sign in to comment.