Revert "bug fixes"
This commit is contained in:
@@ -63,7 +63,7 @@ func (c *registryClient) Subscribe(ctx context.Context, subscription *model.Subs
|
||||
|
||||
// Lookup calls the /lookup endpoint with retry and returns a slice of Subscription.
|
||||
func (c *registryClient) Lookup(ctx context.Context, subscription *model.Subscription) ([]model.Subscription, error) {
|
||||
lookupURL := fmt.Sprintf("%s/lookup", c.config.RegisteryURL)
|
||||
lookupURL := fmt.Sprintf("%s/lookUp", c.config.RegisteryURL)
|
||||
|
||||
jsonData, err := json.Marshal(subscription)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HealthCheckResponse defines the structure for our health check JSON response.
|
||||
type healthCheckResponse struct {
|
||||
Status string `json:"status"`
|
||||
Service string `json:"service"`
|
||||
}
|
||||
|
||||
// healthHandler handles requests to the /health endpoint.
|
||||
func HealthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Ensure the request method is GET.
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
response := healthCheckResponse{
|
||||
Status: "ok",
|
||||
Service: "beckn-adapter",
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
http.Error(w, "Error encoding response", http.StatusInternalServerError)
|
||||
fmt.Printf("Error encoding health check response: %v\n", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestHealthHandler tests the successful GET request to the /health endpoint.
|
||||
func TestHealthHandler(t *testing.T) {
|
||||
req, err := http.NewRequest(http.MethodGet, "/health", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create request: %v", err)
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
HealthHandler(rr, req)
|
||||
|
||||
expContentType := "application/json"
|
||||
expStatus := "ok"
|
||||
expService := "beckn-adapter"
|
||||
|
||||
if status := rr.Code; status != http.StatusOK {
|
||||
t.Fatalf("HealthHandler returned wrong status code: got %v want %v",
|
||||
status, http.StatusOK)
|
||||
}
|
||||
if contentType := rr.Header().Get("Content-Type"); contentType != expContentType {
|
||||
t.Errorf("HealthHandler returned wrong Content-Type: got %v want %v",
|
||||
contentType, expContentType)
|
||||
}
|
||||
|
||||
var response healthCheckResponse
|
||||
err = json.NewDecoder(rr.Body).Decode(&response)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to decode response body: %v", err)
|
||||
}
|
||||
|
||||
if response.Status != expStatus {
|
||||
t.Errorf("HealthHandler returned wrong status in JSON: got %v want %v",
|
||||
response.Status, expStatus)
|
||||
}
|
||||
if response.Service != expService {
|
||||
t.Errorf("HealthHandler returned wrong service in JSON: got %v want %v",
|
||||
response.Service, expService)
|
||||
}
|
||||
}
|
||||
|
||||
// mockResponseWriter is a custom http.ResponseWriter that can simulate an error on Write.
|
||||
type mockResponseWriter struct {
|
||||
httptest.ResponseRecorder
|
||||
writeFail bool
|
||||
}
|
||||
|
||||
func (m *mockResponseWriter) Write(p []byte) (n int, err error) {
|
||||
if m.writeFail {
|
||||
m.writeFail = false
|
||||
return 0, fmt.Errorf("simulated write error")
|
||||
}
|
||||
return m.ResponseRecorder.Write(p)
|
||||
}
|
||||
|
||||
// TestHealthHandlerErrors tests error scenarios for the HealthHandler.
|
||||
func TestHealthHandlerErrors(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
recorder *mockResponseWriter
|
||||
expStatus int
|
||||
expBody string
|
||||
}{
|
||||
{
|
||||
name: "Method Not Allowed",
|
||||
method: http.MethodPost,
|
||||
recorder: &mockResponseWriter{
|
||||
ResponseRecorder: *httptest.NewRecorder(),
|
||||
},
|
||||
expStatus: http.StatusMethodNotAllowed,
|
||||
expBody: "Method not allowed\n",
|
||||
},
|
||||
{
|
||||
name: "JSON Encoding Error",
|
||||
method: http.MethodGet,
|
||||
recorder: &mockResponseWriter{
|
||||
ResponseRecorder: *httptest.NewRecorder(),
|
||||
writeFail: true,
|
||||
},
|
||||
expStatus: http.StatusInternalServerError,
|
||||
expBody: "Error encoding response\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
req, err := http.NewRequest(tt.method, "/health", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create request for %s: %v", tt.name, err)
|
||||
}
|
||||
|
||||
HealthHandler(tt.recorder, req)
|
||||
|
||||
if status := tt.recorder.Code; status != tt.expStatus {
|
||||
t.Errorf("handler returned wrong status code: got %v want %v", status, tt.expStatus)
|
||||
}
|
||||
|
||||
if body := tt.recorder.Body.String(); body != tt.expBody {
|
||||
t.Errorf("handler returned unexpected body: got %q want %q", body, tt.expBody)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/beckn/beckn-onix/core/module/client"
|
||||
"github.com/beckn/beckn-onix/pkg/log"
|
||||
@@ -85,6 +86,9 @@ func (h *stdHandler) stepCtx(r *http.Request, rh http.Header) (*model.StepContex
|
||||
}
|
||||
r.Body.Close()
|
||||
subID := h.subID(r.Context())
|
||||
if len(subID) == 0 {
|
||||
return nil, model.NewBadReqErr(fmt.Errorf("subscriberID not set"))
|
||||
}
|
||||
return &model.StepContext{
|
||||
Context: r.Context(),
|
||||
Request: r,
|
||||
@@ -112,7 +116,7 @@ func route(ctx *model.StepContext, r *http.Request, w http.ResponseWriter, pb de
|
||||
switch ctx.Route.TargetType {
|
||||
case "url":
|
||||
log.Infof(ctx.Context, "Forwarding request to URL: %s", ctx.Route.URL)
|
||||
proxyFunc(ctx, r, w)
|
||||
proxyFunc(r, w, ctx.Route.URL)
|
||||
return
|
||||
case "publisher":
|
||||
if pb == nil {
|
||||
@@ -136,18 +140,16 @@ func route(ctx *model.StepContext, r *http.Request, w http.ResponseWriter, pb de
|
||||
}
|
||||
response.SendAck(w)
|
||||
}
|
||||
func proxy(ctx *model.StepContext, r *http.Request, w http.ResponseWriter) {
|
||||
target := ctx.Route.URL
|
||||
|
||||
// proxy forwards the request to a target URL using a reverse proxy.
|
||||
func proxy(r *http.Request, w http.ResponseWriter, target *url.URL) {
|
||||
r.URL.Scheme = target.Scheme
|
||||
r.URL.Host = target.Host
|
||||
r.URL.Path = target.Path
|
||||
|
||||
r.Header.Set("X-Forwarded-Host", r.Host)
|
||||
|
||||
director := func(req *http.Request) {
|
||||
req.URL = target
|
||||
req.Host = target.Host
|
||||
|
||||
log.Request(req.Context(), req, ctx.Body)
|
||||
}
|
||||
|
||||
proxy := &httputil.ReverseProxy{Director: director}
|
||||
proxy := httputil.NewSingleHostReverseProxy(target)
|
||||
log.Infof(r.Context(), "Proxying request to: %s", target)
|
||||
|
||||
proxy.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
@@ -31,9 +31,6 @@ func newSignStep(signer definition.Signer, km definition.KeyManager) (definition
|
||||
|
||||
// Run executes the signing step.
|
||||
func (s *signStep) Run(ctx *model.StepContext) error {
|
||||
if len(ctx.SubID) == 0 {
|
||||
return model.NewBadReqErr(fmt.Errorf("subscriberID not set"))
|
||||
}
|
||||
keySet, err := s.km.Keyset(ctx, ctx.SubID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get signing key: %w", err)
|
||||
@@ -46,7 +43,7 @@ func (s *signStep) Run(ctx *model.StepContext) error {
|
||||
}
|
||||
|
||||
authHeader := s.generateAuthHeader(ctx.SubID, keySet.UniqueKeyID, createdAt, validTill, sign)
|
||||
log.Debugf(ctx, "Signature generated: %v", sign)
|
||||
|
||||
header := model.AuthHeaderSubscriber
|
||||
if ctx.Role == model.RoleGateway {
|
||||
header = model.AuthHeaderGateway
|
||||
@@ -86,14 +83,11 @@ func (s *validateSignStep) Run(ctx *model.StepContext) error {
|
||||
unauthHeader := fmt.Sprintf("Signature realm=\"%s\",headers=\"(created) (expires) digest\"", ctx.SubID)
|
||||
headerValue := ctx.Request.Header.Get(model.AuthHeaderGateway)
|
||||
if len(headerValue) != 0 {
|
||||
log.Debugf(ctx, "Validating %v Header", model.AuthHeaderGateway)
|
||||
if err := s.validate(ctx, headerValue); err != nil {
|
||||
ctx.RespHeader.Set(model.UnaAuthorizedHeaderGateway, unauthHeader)
|
||||
return model.NewSignValidationErr(fmt.Errorf("failed to validate %s: %w", model.AuthHeaderGateway, err))
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf(ctx, "Validating %v Header", model.AuthHeaderSubscriber)
|
||||
headerValue = ctx.Request.Header.Get(model.AuthHeaderSubscriber)
|
||||
if len(headerValue) == 0 {
|
||||
ctx.RespHeader.Set(model.UnaAuthorizedHeaderSubscriber, unauthHeader)
|
||||
@@ -108,12 +102,13 @@ func (s *validateSignStep) Run(ctx *model.StepContext) error {
|
||||
|
||||
// validate checks the validity of the provided signature header.
|
||||
func (s *validateSignStep) validate(ctx *model.StepContext, value string) error {
|
||||
headerVals, err := parseHeader(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse header")
|
||||
headerParts := strings.Split(value, "|")
|
||||
ids := strings.Split(headerParts[0], "\"")
|
||||
if len(ids) < 2 || len(headerParts) < 3 {
|
||||
return fmt.Errorf("malformed sign header")
|
||||
}
|
||||
log.Debugf(ctx, "Validating Signature for subscriberID: %v", headerVals.SubscriberID)
|
||||
signingPublicKey, _, err := s.km.LookupNPKeys(ctx, headerVals.SubscriberID, headerVals.UniqueID)
|
||||
keyID := headerParts[1]
|
||||
signingPublicKey, _, err := s.km.LookupNPKeys(ctx, ctx.SubID, keyID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get validation key: %w", err)
|
||||
}
|
||||
@@ -123,45 +118,6 @@ func (s *validateSignStep) validate(ctx *model.StepContext, value string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParsedKeyID holds the components from the parsed Authorization header's keyId.
|
||||
type authHeader struct {
|
||||
SubscriberID string
|
||||
UniqueID string
|
||||
Algorithm string
|
||||
}
|
||||
|
||||
// keyID extracts subscriber_id and unique_key_id from the Authorization header.
|
||||
// Example keyId format: "{subscriber_id}|{unique_key_id}|{algorithm}"
|
||||
func parseHeader(header string) (*authHeader, error) {
|
||||
// Example: Signature keyId="bpp.example.com|key-1|ed25519",algorithm="ed25519",...
|
||||
keyIDPart := ""
|
||||
// Look for keyId="<value>"
|
||||
const keyIdPrefix = `keyId="`
|
||||
startIndex := strings.Index(header, keyIdPrefix)
|
||||
if startIndex != -1 {
|
||||
startIndex += len(keyIdPrefix)
|
||||
endIndex := strings.Index(header[startIndex:], `"`)
|
||||
if endIndex != -1 {
|
||||
keyIDPart = strings.TrimSpace(header[startIndex : startIndex+endIndex])
|
||||
}
|
||||
}
|
||||
|
||||
if keyIDPart == "" {
|
||||
return nil, fmt.Errorf("keyId parameter not found in Authorization header")
|
||||
}
|
||||
|
||||
keyIDComponents := strings.Split(keyIDPart, "|")
|
||||
if len(keyIDComponents) != 3 {
|
||||
return nil, fmt.Errorf("keyId parameter has incorrect format, expected 3 components separated by '|', got %d for '%s'", len(keyIDComponents), keyIDPart)
|
||||
}
|
||||
|
||||
return &authHeader{
|
||||
SubscriberID: strings.TrimSpace(keyIDComponents[0]),
|
||||
UniqueID: strings.TrimSpace(keyIDComponents[1]),
|
||||
Algorithm: strings.TrimSpace(keyIDComponents[2]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// validateSchemaStep represents the schema validation step.
|
||||
type validateSchemaStep struct {
|
||||
validator definition.SchemaValidator
|
||||
|
||||
@@ -29,8 +29,6 @@ var handlerProviders = map[handler.Type]Provider{
|
||||
// It iterates over the module configurations, retrieves appropriate handler providers,
|
||||
// and registers the handlers with the HTTP multiplexer.
|
||||
func Register(ctx context.Context, mCfgs []Config, mux *http.ServeMux, mgr handler.PluginManager) error {
|
||||
mux.Handle("/health", http.HandlerFunc(handler.HealthHandler))
|
||||
|
||||
log.Debugf(ctx, "Registering modules with config: %#v", mCfgs)
|
||||
// Iterate over the handlers in the configuration.
|
||||
for _, c := range mCfgs {
|
||||
|
||||
@@ -118,15 +118,7 @@ func TestRegisterSuccess(t *testing.T) {
|
||||
if capturedModuleName != "test-module" {
|
||||
t.Errorf("expected module_id in context to be 'test-module', got %v", capturedModuleName)
|
||||
}
|
||||
// Verifying /health endpoint registration
|
||||
reqHealth := httptest.NewRequest(http.MethodGet, "/health", nil)
|
||||
recHealth := httptest.NewRecorder()
|
||||
mux.ServeHTTP(recHealth, reqHealth)
|
||||
|
||||
if status := recHealth.Code; status != http.StatusOK {
|
||||
t.Errorf("handler for /health returned wrong status code: got %v want %v",
|
||||
status, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRegisterFailure tests scenarios where the handler registration should fail.
|
||||
|
||||
Reference in New Issue
Block a user