-
Notifications
You must be signed in to change notification settings - Fork 225
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: update tests and code for websockets via stdlib
- Loading branch information
1 parent
437047d
commit fea57f9
Showing
12 changed files
with
290 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package handlers | ||
|
||
import ( | ||
"net/http" | ||
"strings" | ||
|
||
"code.cloudfoundry.org/gorouter/config" | ||
"code.cloudfoundry.org/gorouter/logger" | ||
) | ||
|
||
type HopByHop struct { | ||
cfg *config.Config | ||
logger logger.Logger | ||
} | ||
|
||
// NewHopByHop creates a new handler that sanitizes hop-by-hop headers based on the HopByHopHeadersToFilter config | ||
func NewHopByHop(cfg *config.Config, logger logger.Logger) *HopByHop { | ||
return &HopByHop{ | ||
logger: logger, | ||
cfg: cfg, | ||
} | ||
} | ||
|
||
func (h *HopByHop) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) { | ||
h.SanitizeRequestConnection(r) | ||
next(rw, r) | ||
} | ||
|
||
func (h *HopByHop) SanitizeRequestConnection(r *http.Request) { | ||
if len(h.cfg.HopByHopHeadersToFilter) == 0 { | ||
return | ||
} | ||
connections := r.Header.Values("Connection") | ||
for index, connection := range connections { | ||
if connection != "" { | ||
values := strings.Split(connection, ",") | ||
connectionHeader := []string{} | ||
for i := range values { | ||
trimmedValue := strings.TrimSpace(values[i]) | ||
found := false | ||
for _, item := range h.cfg.HopByHopHeadersToFilter { | ||
if strings.ToLower(item) == strings.ToLower(trimmedValue) { | ||
found = true | ||
break | ||
} | ||
} | ||
if !found { | ||
connectionHeader = append(connectionHeader, trimmedValue) | ||
} | ||
} | ||
r.Header[http.CanonicalHeaderKey("Connection")][index] = strings.Join(connectionHeader, ", ") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package handlers_test | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"io" | ||
"net/http" | ||
"net/http/httptest" | ||
|
||
"code.cloudfoundry.org/gorouter/config" | ||
"code.cloudfoundry.org/gorouter/handlers" | ||
logger_fakes "code.cloudfoundry.org/gorouter/logger/fakes" | ||
"code.cloudfoundry.org/gorouter/route" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
"github.com/urfave/negroni/v3" | ||
) | ||
|
||
var _ = Describe("HopByHop", func() { | ||
var ( | ||
handler *negroni.Negroni | ||
|
||
resp http.ResponseWriter | ||
req *http.Request | ||
rawPath string | ||
header http.Header | ||
result *http.Response | ||
responseBody []byte | ||
requestBody *bytes.Buffer | ||
|
||
cfg *config.Config | ||
fakeLogger *logger_fakes.FakeLogger | ||
hopByHop *handlers.HopByHop | ||
|
||
nextCalled bool | ||
) | ||
|
||
nextHandler := negroni.HandlerFunc(func(rw http.ResponseWriter, req *http.Request, next http.HandlerFunc) { | ||
_, err := io.ReadAll(req.Body) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
rw.WriteHeader(http.StatusTeapot) | ||
for name, values := range req.Header { | ||
for _, value := range values { | ||
rw.Header().Set(name, value) | ||
} | ||
} | ||
|
||
rw.Write([]byte("I'm a little teapot, short and stout.")) | ||
|
||
if next != nil { | ||
next(rw, req) | ||
} | ||
|
||
nextCalled = true | ||
}) | ||
|
||
handleRequest := func() { | ||
var err error | ||
handler.ServeHTTP(resp, req) | ||
|
||
result = resp.(*httptest.ResponseRecorder).Result() | ||
responseBody, err = io.ReadAll(result.Body) | ||
Expect(err).NotTo(HaveOccurred()) | ||
result.Body.Close() | ||
} | ||
|
||
BeforeEach(func() { | ||
cfg = &config.Config{ | ||
HopByHopHeadersToFilter: make([]string, 0), | ||
LoadBalance: config.LOAD_BALANCE_RR, | ||
} | ||
requestBody = bytes.NewBufferString("What are you?") | ||
rawPath = "/" | ||
header = http.Header{} | ||
resp = httptest.NewRecorder() | ||
}) | ||
|
||
JustBeforeEach(func() { | ||
fakeLogger = new(logger_fakes.FakeLogger) | ||
handler = negroni.New() | ||
hopByHop = handlers.NewHopByHop(cfg, fakeLogger) | ||
handler.Use(hopByHop) | ||
handler.Use(nextHandler) | ||
|
||
nextCalled = false | ||
|
||
var err error | ||
req, err = http.NewRequest("GET", "http://example.com"+rawPath, requestBody) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
req.Header = header | ||
reqInfo := &handlers.RequestInfo{ | ||
RoutePool: route.NewPool(&route.PoolOpts{}), | ||
} | ||
reqInfo.RoutePool.Put(route.NewEndpoint(&route.EndpointOpts{ | ||
AppId: "fake-app", | ||
Host: "fake-host", | ||
Port: 1234, | ||
PrivateInstanceId: "fake-instance", | ||
})) | ||
req = req.WithContext(context.WithValue(req.Context(), handlers.RequestInfoCtxKey, reqInfo)) | ||
}) | ||
|
||
Context("when HopByHopHeadersToFilter is empty", func() { | ||
BeforeEach(func() { | ||
header.Add("Connection", "X-Forwarded-Proto") | ||
}) | ||
|
||
It("does not touch headers listed in the Connection header", func() { | ||
handleRequest() | ||
Expect(resp.Header().Get("Connection")).To(ContainSubstring("X-Forwarded-Proto")) | ||
Expect(result.StatusCode).To(Equal(http.StatusTeapot)) | ||
Expect(result.Status).To(Equal("418 I'm a teapot")) | ||
Expect(string(responseBody)).To(Equal("I'm a little teapot, short and stout.")) | ||
|
||
}) | ||
It("calls the next handler", func() { | ||
handleRequest() | ||
Expect(nextCalled).To(BeTrue()) | ||
}) | ||
It("doesn't set the reqInfo's RouteEndpoint", func() { | ||
handleRequest() | ||
reqInfo, err := handlers.ContextRequestInfo(req) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
Expect(reqInfo.RouteEndpoint).To(BeNil()) | ||
}) | ||
}) | ||
|
||
Context("when HopByHopHeadersToFilter is set", func() { | ||
BeforeEach(func() { | ||
cfg.HopByHopHeadersToFilter = append(cfg.HopByHopHeadersToFilter, "X-Forwarded-Proto") | ||
header.Add("Connection", "X-Forwarded-Proto") | ||
}) | ||
|
||
It("removes the headers listed in the Connection header", func() { | ||
handleRequest() | ||
Expect(resp.Header().Get("Connection")).To(BeEmpty()) | ||
Expect(result.StatusCode).To(Equal(http.StatusTeapot)) | ||
Expect(result.Status).To(Equal("418 I'm a teapot")) | ||
Expect(string(responseBody)).To(Equal("I'm a little teapot, short and stout.")) | ||
|
||
}) | ||
It("calls the next handler", func() { | ||
handleRequest() | ||
Expect(nextCalled).To(BeTrue()) | ||
}) | ||
It("doesn't set the reqInfo's RouteEndpoint", func() { | ||
handleRequest() | ||
reqInfo, err := handlers.ContextRequestInfo(req) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
Expect(reqInfo.RouteEndpoint).To(BeNil()) | ||
}) | ||
}) | ||
|
||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.