Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: HTTP config #2278

Merged
merged 9 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 12 additions & 21 deletions cli/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
} else {
di.db.Close()
}
if err := di.server.Close(); err != nil {
if err := di.server.Shutdown(ctx); err != nil {

Check warning on line 178 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L178

Added line #L178 was not covered by tests
log.FeedbackInfo(
ctx,
"The server could not be closed successfully",
Expand Down Expand Up @@ -259,40 +259,31 @@
}
}

sOpt := []func(*httpapi.Server){
serverOpts := []httpapi.ServerOpt{

Check warning on line 262 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L262

Added line #L262 was not covered by tests
httpapi.WithAddress(cfg.API.Address),
httpapi.WithRootDir(cfg.Rootdir),
httpapi.WithAllowedOrigins(cfg.API.AllowedOrigins...),
httpapi.WithTLSCertPath(cfg.API.PubKeyPath),
httpapi.WithTLSKeyPath(cfg.API.PrivKeyPath),

Check warning on line 266 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L265-L266

Added lines #L265 - L266 were not covered by tests
}

if cfg.API.TLS {
sOpt = append(
sOpt,
httpapi.WithTLS(),
httpapi.WithSelfSignedCert(cfg.API.PubKeyPath, cfg.API.PrivKeyPath),
httpapi.WithCAEmail(cfg.API.Email),
)
}

var server *httpapi.Server
var handler *httpapi.Handler

Check warning on line 269 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L269

Added line #L269 was not covered by tests
if node != nil {
server, err = httpapi.NewServer(node, sOpt...)
handler, err = httpapi.NewHandler(node)

Check warning on line 271 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L271

Added line #L271 was not covered by tests
} else {
server, err = httpapi.NewServer(db, sOpt...)
handler, err = httpapi.NewHandler(db)

Check warning on line 273 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L273

Added line #L273 was not covered by tests
}
if err != nil {
return nil, errors.Wrap("failed to create http server", err)
return nil, errors.Wrap("failed to create http handler", err)

Check warning on line 276 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L276

Added line #L276 was not covered by tests
}
if err := server.Listen(ctx); err != nil {
return nil, errors.Wrap(fmt.Sprintf("failed to listen on TCP address %v", server.Addr), err)
server, err := httpapi.NewServer(handler, serverOpts...)
if err != nil {
return nil, errors.Wrap("failed to create http server", err)

Check warning on line 280 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L278-L280

Added lines #L278 - L280 were not covered by tests
}
// save the address on the config in case the port number was set to random
cfg.API.Address = server.AssignedAddr()

// run the server in a separate goroutine
go func() {
log.FeedbackInfo(ctx, fmt.Sprintf("Providing HTTP API at %s.", cfg.API.AddressToURL()))
if err := server.Run(ctx); err != nil && !errors.Is(err, http.ErrServerClosed) {
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {

Check warning on line 286 in cli/start.go

View check run for this annotation

Codecov / codecov/patch

cli/start.go#L286

Added line #L286 was not covered by tests
log.FeedbackErrorE(ctx, "Failed to run the HTTP server", err)
if node != nil {
node.Close()
Expand Down
12 changes: 6 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,13 @@
if !filepath.IsAbs(cfg.v.GetString("datastore.badger.path")) {
cfg.v.Set("datastore.badger.path", filepath.Join(cfg.Rootdir, cfg.v.GetString("datastore.badger.path")))
}
if !filepath.IsAbs(cfg.v.GetString("api.privkeypath")) {
cfg.v.Set("api.privkeypath", filepath.Join(cfg.Rootdir, cfg.v.GetString("api.privkeypath")))
privKeyPath := cfg.v.GetString("api.privkeypath")
if privKeyPath != "" && !filepath.IsAbs(privKeyPath) {
cfg.v.Set("api.privkeypath", filepath.Join(cfg.Rootdir, privKeyPath))

Check warning on line 212 in config/config.go

View check run for this annotation

Codecov / codecov/patch

config/config.go#L212

Added line #L212 was not covered by tests
}
if !filepath.IsAbs(cfg.v.GetString("api.pubkeypath")) {
cfg.v.Set("api.pubkeypath", filepath.Join(cfg.Rootdir, cfg.v.GetString("api.pubkeypath")))
pubKeyPath := cfg.v.GetString("api.pubkeypath")
if pubKeyPath != "" && !filepath.IsAbs(pubKeyPath) {
cfg.v.Set("api.pubkeypath", filepath.Join(cfg.Rootdir, pubKeyPath))

Check warning on line 216 in config/config.go

View check run for this annotation

Codecov / codecov/patch

config/config.go#L216

Added line #L216 was not covered by tests
}

// log.logger configuration as a string
Expand Down Expand Up @@ -303,8 +305,6 @@
Address: "localhost:9181",
TLS: false,
AllowedOrigins: []string{},
PubKeyPath: "certs/server.key",
PrivKeyPath: "certs/server.crt",
Email: DefaultAPIEmail,
}
}
Expand Down
4 changes: 2 additions & 2 deletions config/configfile_yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ api:
# The list of origins a cross-domain request can be executed from.
# allowed-origins: {{ .API.AllowedOrigins }}
# The path to the public key file. Ignored if domains is set.
pubkeypath: {{ .API.PubKeyPath }}
# pubkeypath: {{ .API.PubKeyPath }}
# The path to the private key file. Ignored if domains is set.
privkeypath: {{ .API.PrivKeyPath }}
# privkeypath: {{ .API.PrivKeyPath }}
# Email address to let the CA (Let's Encrypt) send notifications via email when there are issues (optional).
# email: {{ .API.Email }}

Expand Down
10 changes: 2 additions & 8 deletions http/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"github.com/sourcenetwork/defradb/datastore"

"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)

// Version is the identifier for the current API version.
Expand Down Expand Up @@ -69,22 +68,17 @@ type Handler struct {
txs *sync.Map
}

func NewHandler(db client.DB, opts ServerOptions) (*Handler, error) {
func NewHandler(db client.DB) (*Handler, error) {
router, err := NewApiRouter()
if err != nil {
return nil, err
}
txs := &sync.Map{}

mux := chi.NewMux()
mux.Use(
middleware.RequestLogger(&logFormatter{}),
middleware.Recoverer,
CorsMiddleware(opts),
)
mux.Route("/api/"+Version, func(r chi.Router) {
r.Use(
ApiMiddleware(db, txs, opts),
ApiMiddleware(db, txs),
TransactionMiddleware,
StoreMiddleware,
)
Expand Down
12 changes: 6 additions & 6 deletions http/handler_ccip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestCCIPGet_WithValidData(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, url, nil)
rec := httptest.NewRecorder()

handler, err := NewHandler(cdb, ServerOptions{})
handler, err := NewHandler(cdb)
require.NoError(t, err)
handler.ServeHTTP(rec, req)

Expand Down Expand Up @@ -88,7 +88,7 @@ func TestCCIPGet_WithSubscription(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, url, nil)
rec := httptest.NewRecorder()

handler, err := NewHandler(cdb, ServerOptions{})
handler, err := NewHandler(cdb)
require.NoError(t, err)
handler.ServeHTTP(rec, req)

Expand All @@ -106,7 +106,7 @@ func TestCCIPGet_WithInvalidData(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, url, nil)
rec := httptest.NewRecorder()

handler, err := NewHandler(cdb, ServerOptions{})
handler, err := NewHandler(cdb)
require.NoError(t, err)
handler.ServeHTTP(rec, req)

Expand Down Expand Up @@ -135,7 +135,7 @@ func TestCCIPPost_WithValidData(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "http://localhost:9181/api/v0/ccip", bytes.NewBuffer(body))
rec := httptest.NewRecorder()

handler, err := NewHandler(cdb, ServerOptions{})
handler, err := NewHandler(cdb)
require.NoError(t, err)
handler.ServeHTTP(rec, req)

Expand Down Expand Up @@ -167,7 +167,7 @@ func TestCCIPPost_WithInvalidGraphQLRequest(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "http://localhost:9181/api/v0/ccip", bytes.NewBuffer(body))
rec := httptest.NewRecorder()

handler, err := NewHandler(cdb, ServerOptions{})
handler, err := NewHandler(cdb)
require.NoError(t, err)
handler.ServeHTTP(rec, req)

Expand All @@ -181,7 +181,7 @@ func TestCCIPPost_WithInvalidBody(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "http://localhost:9181/api/v0/ccip", nil)
rec := httptest.NewRecorder()

handler, err := NewHandler(cdb, ServerOptions{})
handler, err := NewHandler(cdb)
require.NoError(t, err)
handler.ServeHTTP(rec, req)

Expand Down
12 changes: 4 additions & 8 deletions http/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ var (
)

// CorsMiddleware handles cross origin request
func CorsMiddleware(opts ServerOptions) func(http.Handler) http.Handler {
func CorsMiddleware(allowedOrigins []string) func(http.Handler) http.Handler {
return cors.Handler(cors.Options{
AllowOriginFunc: func(r *http.Request, origin string) bool {
if slices.Contains(opts.AllowedOrigins, "*") {
if slices.Contains(allowedOrigins, "*") {
return true
}
return slices.Contains(opts.AllowedOrigins, strings.ToLower(origin))
return slices.Contains(allowedOrigins, strings.ToLower(origin))
},
AllowedMethods: []string{"GET", "HEAD", "POST", "PATCH", "DELETE"},
AllowedHeaders: []string{"Content-Type"},
Expand All @@ -71,13 +71,9 @@ func CorsMiddleware(opts ServerOptions) func(http.Handler) http.Handler {
}

// ApiMiddleware sets the required context values for all API requests.
func ApiMiddleware(db client.DB, txs *sync.Map, opts ServerOptions) func(http.Handler) http.Handler {
func ApiMiddleware(db client.DB, txs *sync.Map) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if opts.TLS.HasValue() {
rw.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
}

ctx := req.Context()
ctx = context.WithValue(ctx, dbContextKey, db)
ctx = context.WithValue(ctx, txsContextKey, txs)
Expand Down
Loading
Loading