mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-09-21 07:32:00 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
749dad4ed1 | ||
|
|
d6c5740f9c |
+113
-102
@@ -306,15 +306,16 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st
|
|||||||
|
|
||||||
txErr := h.db.RunInTransaction(ctx, func(tx common.Database) error {
|
txErr := h.db.RunInTransaction(ctx, func(tx common.Database) error {
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "read",
|
||||||
ID: id,
|
Options: options,
|
||||||
Writer: w,
|
ID: id,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeRead, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeRead, hookCtx); err != nil {
|
||||||
statusCode, errCode, errMsg = http.StatusInternalServerError, "hook_error", "BeforeRead hook failed"
|
statusCode, errCode, errMsg = http.StatusInternalServerError, "hook_error", "BeforeRead hook failed"
|
||||||
@@ -722,15 +723,16 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
|
|||||||
var nestedResult *common.ProcessResult
|
var nestedResult *common.ProcessResult
|
||||||
err := h.db.RunInTransaction(ctx, func(tx common.Database) error {
|
err := h.db.RunInTransaction(ctx, func(tx common.Database) error {
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "create",
|
||||||
Data: v,
|
Options: options,
|
||||||
Writer: w,
|
Data: v,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
||||||
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
||||||
@@ -769,15 +771,16 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
|
|||||||
var responseData interface{} = v
|
var responseData interface{} = v
|
||||||
err := h.db.RunInTransaction(ctx, func(tx common.Database) error {
|
err := h.db.RunInTransaction(ctx, func(tx common.Database) error {
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "create",
|
||||||
Data: v,
|
Options: options,
|
||||||
Writer: w,
|
Data: v,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
||||||
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
||||||
@@ -851,15 +854,16 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
|
|||||||
|
|
||||||
for _, item := range v {
|
for _, item := range v {
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "create",
|
||||||
Data: item,
|
Options: options,
|
||||||
Writer: w,
|
Data: item,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
||||||
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
||||||
@@ -898,15 +902,16 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
|
|||||||
err := h.db.RunInTransaction(ctx, func(tx common.Database) error {
|
err := h.db.RunInTransaction(ctx, func(tx common.Database) error {
|
||||||
for _, item := range v {
|
for _, item := range v {
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "create",
|
||||||
Data: item,
|
Options: options,
|
||||||
Writer: w,
|
Data: item,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
||||||
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
||||||
@@ -982,15 +987,16 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
|
|||||||
for _, item := range v {
|
for _, item := range v {
|
||||||
if itemMap, ok := item.(map[string]interface{}); ok {
|
if itemMap, ok := item.(map[string]interface{}); ok {
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "create",
|
||||||
Data: itemMap,
|
Options: options,
|
||||||
Writer: w,
|
Data: itemMap,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
||||||
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
||||||
@@ -1035,15 +1041,16 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "create",
|
||||||
Data: itemMap,
|
Options: options,
|
||||||
Writer: w,
|
Data: itemMap,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeCreate, hookCtx); err != nil {
|
||||||
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
return fmt.Errorf("BeforeCreate hook failed: %w", err)
|
||||||
@@ -1166,16 +1173,17 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, url
|
|||||||
// they must run before the existence-check select so that select is
|
// they must run before the existence-check select so that select is
|
||||||
// also subject to RLS on this connection/transaction.
|
// also subject to RLS on this connection/transaction.
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "update",
|
||||||
ID: urlID,
|
Options: options,
|
||||||
Data: updates,
|
ID: urlID,
|
||||||
Writer: w,
|
Data: updates,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeUpdate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeUpdate, hookCtx); err != nil {
|
||||||
@@ -1387,16 +1395,17 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, url
|
|||||||
|
|
||||||
// Execute BeforeUpdate hooks inside transaction
|
// Execute BeforeUpdate hooks inside transaction
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "update",
|
||||||
ID: itemIDStr,
|
Options: options,
|
||||||
Data: item,
|
ID: itemIDStr,
|
||||||
Writer: w,
|
Data: item,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeUpdate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeUpdate, hookCtx); err != nil {
|
||||||
@@ -1543,16 +1552,17 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, url
|
|||||||
|
|
||||||
// Execute BeforeUpdate hooks inside transaction
|
// Execute BeforeUpdate hooks inside transaction
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
Options: options,
|
Operation: "update",
|
||||||
ID: itemIDStr,
|
Options: options,
|
||||||
Data: itemMap,
|
ID: itemIDStr,
|
||||||
Writer: w,
|
Data: itemMap,
|
||||||
Tx: tx,
|
Writer: w,
|
||||||
|
Tx: tx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeUpdate, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeUpdate, hookCtx); err != nil {
|
||||||
@@ -1648,15 +1658,16 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
|
|||||||
|
|
||||||
// Execute BeforeDelete hooks (covers model-rule checks before any deletion)
|
// Execute BeforeDelete hooks (covers model-rule checks before any deletion)
|
||||||
hookCtx := &HookContext{
|
hookCtx := &HookContext{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Handler: h,
|
Handler: h,
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
Entity: entity,
|
Entity: entity,
|
||||||
Model: model,
|
Model: model,
|
||||||
ID: id,
|
Operation: "delete",
|
||||||
Data: data,
|
ID: id,
|
||||||
Writer: w,
|
Data: data,
|
||||||
Tx: h.db,
|
Writer: w,
|
||||||
|
Tx: h.db,
|
||||||
}
|
}
|
||||||
if err := h.hooks.ExecuteBeforeOp(BeforeDelete, hookCtx); err != nil {
|
if err := h.hooks.ExecuteBeforeOp(BeforeDelete, hookCtx); err != nil {
|
||||||
logger.Error("BeforeDelete hook failed: %v", err)
|
logger.Error("BeforeDelete hook failed: %v", err)
|
||||||
|
|||||||
@@ -379,6 +379,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st
|
|||||||
Entity: entity,
|
Entity: entity,
|
||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
Operation: "read",
|
||||||
Options: options,
|
Options: options,
|
||||||
ID: id,
|
ID: id,
|
||||||
Writer: w,
|
Writer: w,
|
||||||
@@ -1236,6 +1237,7 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
|
|||||||
Entity: entity,
|
Entity: entity,
|
||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
Operation: "create",
|
||||||
Options: options,
|
Options: options,
|
||||||
Data: data,
|
Data: data,
|
||||||
Writer: w,
|
Writer: w,
|
||||||
@@ -1335,6 +1337,7 @@ func (h *Handler) handleCreate(ctx context.Context, w common.ResponseWriter, dat
|
|||||||
Entity: entity,
|
Entity: entity,
|
||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
Operation: "create",
|
||||||
Options: options,
|
Options: options,
|
||||||
Data: modelValue,
|
Data: modelValue,
|
||||||
Writer: w,
|
Writer: w,
|
||||||
@@ -1489,6 +1492,7 @@ func (h *Handler) handleUpdate(ctx context.Context, w common.ResponseWriter, id
|
|||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
Tx: tx,
|
Tx: tx,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
Operation: "update",
|
||||||
Options: options,
|
Options: options,
|
||||||
ID: id,
|
ID: id,
|
||||||
Data: dataMap,
|
Data: dataMap,
|
||||||
@@ -1686,6 +1690,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
|
|||||||
Entity: entity,
|
Entity: entity,
|
||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
Operation: "delete",
|
||||||
ID: itemID,
|
ID: itemID,
|
||||||
Writer: w,
|
Writer: w,
|
||||||
Tx: tx,
|
Tx: tx,
|
||||||
@@ -1760,6 +1765,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
|
|||||||
Entity: entity,
|
Entity: entity,
|
||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
Operation: "delete",
|
||||||
ID: itemIDStr,
|
ID: itemIDStr,
|
||||||
Writer: w,
|
Writer: w,
|
||||||
Tx: tx,
|
Tx: tx,
|
||||||
@@ -1818,6 +1824,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
|
|||||||
Entity: entity,
|
Entity: entity,
|
||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
Operation: "delete",
|
||||||
ID: itemIDStr,
|
ID: itemIDStr,
|
||||||
Writer: w,
|
Writer: w,
|
||||||
Tx: tx,
|
Tx: tx,
|
||||||
@@ -1902,6 +1909,7 @@ func (h *Handler) handleDelete(ctx context.Context, w common.ResponseWriter, id
|
|||||||
Entity: entity,
|
Entity: entity,
|
||||||
TableName: tableName,
|
TableName: tableName,
|
||||||
Model: model,
|
Model: model,
|
||||||
|
Operation: "delete",
|
||||||
ID: id,
|
ID: id,
|
||||||
Writer: w,
|
Writer: w,
|
||||||
Tx: h.db,
|
Tx: h.db,
|
||||||
|
|||||||
@@ -5,8 +5,10 @@
|
|||||||
package quickproxy
|
package quickproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
@@ -191,6 +193,15 @@ func (s *Service) Handler(fallback http.Handler) http.Handler {
|
|||||||
|
|
||||||
for i := range s.rules {
|
for i := range s.rules {
|
||||||
s.rules[i].proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, _ error) {
|
s.rules[i].proxy.ErrorHandler = func(w http.ResponseWriter, r *http.Request, _ error) {
|
||||||
|
// ReverseProxy consumes and closes r.Body while attempting the
|
||||||
|
// upstream request, even when that attempt fails (per the
|
||||||
|
// http.RoundTripper contract). Restore a fresh copy from
|
||||||
|
// r.GetBody, set below, before handing the request to fallback.
|
||||||
|
if r.GetBody != nil {
|
||||||
|
if body, err := r.GetBody(); err == nil {
|
||||||
|
r.Body = body
|
||||||
|
}
|
||||||
|
}
|
||||||
fallback.ServeHTTP(w, r)
|
fallback.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,6 +212,22 @@ func (s *Service) Handler(fallback http.Handler) http.Handler {
|
|||||||
fallback.ServeHTTP(w, r)
|
fallback.ServeHTTP(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Buffer the body so it can be replayed to fallback if the upstream
|
||||||
|
// attempt fails; see ErrorHandler above.
|
||||||
|
if r.Body != nil && r.Body != http.NoBody {
|
||||||
|
bodyBytes, err := io.ReadAll(r.Body)
|
||||||
|
r.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "failed to read request body", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.Body = io.NopCloser(bytes.NewReader(bodyBytes))
|
||||||
|
r.GetBody = func() (io.ReadCloser, error) {
|
||||||
|
return io.NopCloser(bytes.NewReader(bodyBytes)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rule.proxy.ServeHTTP(w, r)
|
rule.proxy.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -130,6 +131,75 @@ func TestHandler_UnreachableUpstreamFallsBack(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHandler_UnreachableUpstreamFallsBackWithBody(t *testing.T) {
|
||||||
|
// A closed listener address: nothing is listening, so dialing fails and
|
||||||
|
// ReverseProxy invokes ErrorHandler. The fallback handler must still see
|
||||||
|
// the original request body, even though ReverseProxy consumed and
|
||||||
|
// closed it while attempting (and failing) the upstream request.
|
||||||
|
unreachable := "http://127.0.0.1:1"
|
||||||
|
|
||||||
|
svc, err := NewService([]Rule{{URLPrefix: "/", Target: unreachable}}, WithTimeout(500*time.Millisecond))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewService: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
echoBody := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("fallback reading body: %v", err)
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write(body)
|
||||||
|
})
|
||||||
|
|
||||||
|
handler := svc.Handler(echoBody)
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodPost, "/submit", strings.NewReader("payload=1"))
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(rr, req)
|
||||||
|
|
||||||
|
if rr.Code != http.StatusOK {
|
||||||
|
t.Fatalf("status = %d, want 200", rr.Code)
|
||||||
|
}
|
||||||
|
if got := rr.Body.String(); got != "payload=1" {
|
||||||
|
t.Fatalf("body = %q, want payload=1", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_404FallsBackWithBody(t *testing.T) {
|
||||||
|
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
}))
|
||||||
|
defer upstream.Close()
|
||||||
|
|
||||||
|
svc, err := NewService([]Rule{{URLPrefix: "/", Target: upstream.URL}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewService: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
echoBody := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := io.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("fallback reading body: %v", err)
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write(body)
|
||||||
|
})
|
||||||
|
|
||||||
|
handler := svc.Handler(echoBody)
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodPut, "/missing", strings.NewReader("payload=2"))
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(rr, req)
|
||||||
|
|
||||||
|
if rr.Code != http.StatusOK {
|
||||||
|
t.Fatalf("status = %d, want 200", rr.Code)
|
||||||
|
}
|
||||||
|
if got := rr.Body.String(); got != "payload=2" {
|
||||||
|
t.Fatalf("body = %q, want payload=2", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHandler_NonNotFoundErrorsPassThrough(t *testing.T) {
|
func TestHandler_NonNotFoundErrorsPassThrough(t *testing.T) {
|
||||||
codes := []int{http.StatusOK, http.StatusForbidden, http.StatusBadRequest, http.StatusInternalServerError}
|
codes := []int{http.StatusOK, http.StatusForbidden, http.StatusBadRequest, http.StatusInternalServerError}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user