Skip to content

Commit c05d3a5

Browse files
author
Mike Zorn
authored
fix: [FUN-983] Set CORS headers consistently for SDK & API cases (#614)
* Apply cors for API via normal middleware * Used canned gorilla cors handler * Include options in routes * Apply CORS for /dev routes * remove extraneous CORS tests handler was removed for gorilla built in
1 parent 303794c commit c05d3a5

File tree

7 files changed

+84
-169
lines changed

7 files changed

+84
-169
lines changed

internal/dev_server/api/api.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ info:
77
those flags.
88
version: 1.0.0
99
servers:
10-
- url: "http"
10+
- url: "http://localhost:8765/dev"
1111
paths:
12-
/dev/backup:
12+
/backup:
1313
get:
1414
summary: get the backup
1515
operationId: getBackup
@@ -28,7 +28,7 @@ paths:
2828
responses:
2929
200:
3030
description: 'Backup restored'
31-
/dev/projects:
31+
/projects:
3232
get:
3333
summary: lists all projects that have been configured for the dev server
3434
operationId: getProjects
@@ -43,7 +43,7 @@ paths:
4343
items:
4444
type: string
4545
uniqueItems: true
46-
/dev/projects/{projectKey}:
46+
/projects/{projectKey}:
4747
get:
4848
summary: get the specified project and its configuration for syncing from the LaunchDarkly Service
4949
operationId: getProject
@@ -113,7 +113,7 @@ paths:
113113
$ref: "#/components/responses/ErrorResponse"
114114
409:
115115
$ref: "#/components/responses/ErrorResponse"
116-
/dev/projects/{projectKey}/overrides:
116+
/projects/{projectKey}/overrides:
117117
delete:
118118
summary: remove all overrides for the given project
119119
operationId: deleteOverrides
@@ -124,7 +124,7 @@ paths:
124124
description: OK. All overrides were removed
125125
404:
126126
$ref: "#/components/responses/ErrorResponse"
127-
/dev/projects/{projectKey}/overrides/{flagKey}:
127+
/projects/{projectKey}/overrides/{flagKey}:
128128
put:
129129
summary: override flag value with value provided in the body
130130
operationId: putOverrideFlag
@@ -155,7 +155,7 @@ paths:
155155
description: OK. override removed
156156
404:
157157
description: no matching override found
158-
/dev/projects/{projectKey}/environments:
158+
/projects/{projectKey}/environments:
159159
get:
160160
operationId: getEnvironments
161161
summary: list all environments for the given project

internal/dev_server/api/cors.go

Lines changed: 0 additions & 31 deletions
This file was deleted.

internal/dev_server/api/cors_test.go

Lines changed: 0 additions & 63 deletions
This file was deleted.

internal/dev_server/api/server.gen.go

Lines changed: 33 additions & 33 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/dev_server/dev_server.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,32 @@ func (c LDClient) RunServer(ctx context.Context, serverParams ServerParams) {
5959
ResponseErrorHandlerFunc: api.ResponseErrorHandler,
6060
})
6161
r := mux.NewRouter()
62+
r.Use(handlers.RecoveryHandler(handlers.PrintRecoveryStack(true)))
6263
r.Use(adapters.Middleware(*ldClient, serverParams.DevStreamURI))
6364
r.Use(model.StoreMiddleware(sqlStore))
6465
r.Use(model.ObserversMiddleware(observers))
6566
r.Handle("/", http.RedirectHandler("/ui/", http.StatusFound))
6667
r.Handle("/ui", http.RedirectHandler("/ui/", http.StatusMovedPermanently))
6768
r.PathPrefix("/ui/").Handler(http.StripPrefix("/ui/", ui.AssetHandler))
69+
6870
sdk.BindRoutes(r)
69-
handler := api.HandlerFromMux(apiServer, r)
70-
handler = api.CorsHeadersWithConfig(serverParams.CorsEnabled, serverParams.CorsOrigin)(handler)
71-
handler = handlers.CombinedLoggingHandler(os.Stdout, handler)
72-
handler = handlers.RecoveryHandler(handlers.PrintRecoveryStack(true))(handler)
71+
72+
apiRouter := r.PathPrefix("/dev").Subrouter()
73+
if serverParams.CorsEnabled {
74+
apiRouter.Use(handlers.CORS(
75+
handlers.AllowedOrigins([]string{serverParams.CorsOrigin}),
76+
handlers.AllowedHeaders([]string{"Content-Type", "Content-Length", "Accept-Encoding", "X-Requested-With"}),
77+
handlers.ExposedHeaders([]string{"Date", "Content-Length"}),
78+
handlers.AllowedMethods([]string{"GET", "POST", "PUT", "PATCH", "DELETE"}),
79+
handlers.MaxAge(300),
80+
))
81+
apiRouter.PathPrefix("/").Methods(http.MethodOptions).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
82+
// request should have been handled in the CORS middleware
83+
// This route is needed so that gorilla will not 404 for options requests
84+
panic("options handler running. This indicates a misconfiguration of routes")
85+
})
86+
}
87+
api.HandlerFromMux(apiServer, apiRouter) // this method actually mutates the passed router.
7388

7489
ctx = adapters.WithApiAndSdk(ctx, *ldClient, serverParams.DevStreamURI)
7590
ctx = model.SetObserversOnContext(ctx, observers)
@@ -78,6 +93,7 @@ func (c LDClient) RunServer(ctx context.Context, serverParams ServerParams) {
7893
if syncErr != nil {
7994
log.Fatal(syncErr)
8095
}
96+
handler := handlers.CombinedLoggingHandler(os.Stdout, r)
8197

8298
addr := fmt.Sprintf("0.0.0.0:%s", serverParams.Port)
8399
log.Printf("Server running on %s", addr)

internal/dev_server/sdk/cors.go

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
11
package sdk
22

3-
import "net/http"
3+
import (
4+
"github.com/gorilla/handlers"
5+
)
46

5-
func CorsHeaders(handler http.Handler) http.Handler {
6-
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
7-
writer.Header().Set("Access-Control-Allow-Origin", "*")
8-
writer.Header().Set("Access-Control-Allow-Methods", "GET,OPTIONS")
9-
writer.Header().Set("Access-Control-Allow-Credentials", "true")
10-
writer.Header().Set("Access-Control-Allow-Headers", "Cache-Control,Content-Type,Content-Length,Accept-Encoding,X-LaunchDarkly-User-Agent,X-LaunchDarkly-Payload-ID,X-LaunchDarkly-Wrapper,X-LaunchDarkly-Event-Schema,X-LaunchDarkly-Tags")
11-
writer.Header().Set("Access-Control-Expose-Headers", "Date")
12-
writer.Header().Set("Access-Control-Max-Age", "300")
13-
handler.ServeHTTP(writer, request)
14-
})
15-
}
7+
var CorsHeaders = handlers.CORS(
8+
handlers.AllowedOrigins([]string{"*"}),
9+
handlers.AllowedMethods([]string{"GET"}),
10+
handlers.AllowCredentials(),
11+
handlers.ExposedHeaders([]string{"Date"}),
12+
handlers.AllowedHeaders([]string{"Cache-Control", "Content-Type", "Content-Length", "Accept-Encoding", "X-LaunchDarkly-Event-Schema", "X-LaunchDarkly-User-Agent", "X-LaunchDarkly-Payload-ID", "X-LaunchDarkly-Wrapper", "X-LaunchDarkly-Tags"}),
13+
handlers.MaxAge(300),
14+
)
1615

17-
func EventsCorsHeaders(handler http.Handler) http.Handler {
18-
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
19-
writer.Header().Set("Access-Control-Allow-Origin", "*")
20-
writer.Header().Set("Access-Control-Allow-Methods", "POST,OPTIONS")
21-
writer.Header().Set("Access-Control-Allow-Credentials", "true")
22-
writer.Header().Set("Access-Control-Allow-Headers", "Accept,Content-Type,Content-Length,Accept-Encoding,X-LaunchDarkly-Event-Schema,X-LaunchDarkly-User-Agent,X-LaunchDarkly-Payload-ID,X-LaunchDarkly-Wrapper,X-LaunchDarkly-Tags")
23-
writer.Header().Set("Access-Control-Expose-Headers", "Date")
24-
writer.Header().Set("Access-Control-Max-Age", "300")
25-
handler.ServeHTTP(writer, request)
26-
})
27-
}
16+
var EventsCorsHeaders = handlers.CORS(
17+
handlers.AllowedOrigins([]string{"*"}),
18+
handlers.AllowedMethods([]string{"POST"}),
19+
handlers.AllowCredentials(),
20+
handlers.AllowedHeaders([]string{"Accept", "Content-Type", "Content-Length", "Accept-Encoding", "X-LaunchDarkly-Event-Schema", "X-LaunchDarkly-User-Agent", "X-LaunchDarkly-Payload-ID", "X-LaunchDarkly-Wrapper", "X-LaunchDarkly-Tags"}),
21+
handlers.ExposedHeaders([]string{"Date"}),
22+
handlers.MaxAge(300),
23+
)

0 commit comments

Comments
 (0)