| @@ -34,10 +34,18 @@ type handlerInterceptorNoStreamTestHost struct { · 33 unmodified lines |
| 34 | 34 | *handlerInterceptorTestHost |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | +type handlerInterceptorDisabledRequestTestHost struct { |
| 38 | + *handlerInterceptorTestHost |
| 39 | +} |
| 40 | + |
| 37 | 41 | func (h *handlerInterceptorNoStreamTestHost) HasStreamInterceptors() bool { |
| 38 | 42 | return false |
| 39 | 43 | } |
| 40 | 44 | |
| 45 | +func (h *handlerInterceptorDisabledRequestTestHost) HasRequestInterceptors() bool { |
| 46 | + return false |
| 47 | +} |
| 48 | + |
| 41 | 49 | func (h *handlerInterceptorTestHost) InterceptRequestBeforeAuth(ctx context.Context, req pluginapi.RequestInterceptRequest) pluginapi.RequestInterceptResponse { |
| 42 | 50 | if h != nil && h.interceptRequestBeforeAuth != nil { |
| 43 | 51 | return h.interceptRequestBeforeAuth(ctx, req) |
| @@ -566,6 +574,80 @@ func TestHandlerRequestInterceptorRewritesExecutorRequest(t *testing.T) { · 522 unmodified lines |
| 566 | 574 | } |
| 567 | 575 | } |
| 568 | 576 | |
| 577 | +func TestHandlerSkipsDisabledRequestInterceptorsWithoutCopyingPayload(t *testing.T) { |
| 578 | + payload := []byte(`{"model":"disabled-interceptor-model"}`) |
| 579 | + called := false |
| 580 | + handler := NewBaseAPIHandlers(&sdkconfig.SDKConfig{}, nil) |
| 581 | + handler.SetPluginHost(&handlerInterceptorDisabledRequestTestHost{ |
| 582 | + handlerInterceptorTestHost: &handlerInterceptorTestHost{ |
| 583 | + interceptRequestBeforeAuth: func(context.Context, pluginapi.RequestInterceptRequest) pluginapi.RequestInterceptResponse { |
| 584 | + called = true |
| 585 | + return pluginapi.RequestInterceptResponse{Body: []byte(`{"unexpected":true}`)} |
| 586 | + }, |
| 587 | + }, |
| 588 | + }) |
| 589 | + |
| 590 | + req := coreexecutor.Request{Model: "disabled-interceptor-model", Payload: payload} |
| 591 | + opts := coreexecutor.Options{OriginalRequest: payload} |
| 592 | + gotReq, gotOpts, err := handler.applyRequestInterceptorsBeforeAuth(context.Background(), "openai", req.Model, "test-req", req, opts, "") |
| 593 | + if err != nil { |
| 594 | + t.Fatalf("unexpected error: %v", err) |
| 595 | + } |
| 596 | + |
| 597 | + if called { |
| 598 | + t.Fatal("disabled request interceptor was called") |
| 599 | + } |
| 600 | + if len(gotReq.Payload) != len(payload) || &gotReq.Payload[0] != &payload[0] { |
| 601 | + t.Fatal("request payload was copied") |
| 602 | + } |
| 603 | + if len(gotOpts.OriginalRequest) != len(payload) || &gotOpts.OriginalRequest[0] != &payload[0] { |
| 604 | + t.Fatal("original request was copied") |
| 605 | + } |
| 606 | +} |
| 607 | + |
| 608 | +func BenchmarkHandlerRequestInterceptors(b *testing.B) { |
| 609 | + sizes := []struct { |
| 610 | + name string |
| 611 | + bytes int |
| 612 | + }{ |
| 613 | + {name: "1KiB", bytes: 1 << 10}, |
| 614 | + {name: "1MiB", bytes: 1 << 20}, |
| 615 | + {name: "8MiB", bytes: 8 << 20}, |
| 616 | + } |
| 617 | + hosts := []struct { |
| 618 | + name string |
| 619 | + host PluginInterceptorHost |
| 620 | + }{ |
| 621 | + { |
| 622 | + name: "disabled", |
| 623 | + host: &handlerInterceptorDisabledRequestTestHost{ |
| 624 | + handlerInterceptorTestHost: &handlerInterceptorTestHost{}, |
| 625 | + }, |
| 626 | + }, |
| 627 | + {name: "active", host: &handlerInterceptorTestHost{}}, |
| 628 | + } |
| 629 | + |
| 630 | + for _, size := range sizes { |
| 631 | + payload := make([]byte, size.bytes) |
| 632 | + req := coreexecutor.Request{Model: "benchmark-model", Payload: payload} |
| 633 | + opts := coreexecutor.Options{OriginalRequest: payload} |
| 634 | + for _, host := range hosts { |
| 635 | + b.Run(host.name+"/"+size.name, func(b *testing.B) { |
| 636 | + handler := NewBaseAPIHandlers(&sdkconfig.SDKConfig{}, nil) |
| 637 | + handler.SetPluginHost(host.host) |
| 638 | + b.ReportAllocs() |
| 639 | + b.ResetTimer() |
| 640 | + for range b.N { |
| 641 | + gotReq, gotOpts, _ := handler.applyRequestInterceptorsBeforeAuth(context.Background(), "openai", req.Model, "benchmark-req", req, opts, "") |
| 642 | + if len(gotReq.Payload) != size.bytes || len(gotOpts.OriginalRequest) != size.bytes { |
| 643 | + b.Fatal("request payload length changed") |
| 644 | + } |
| 645 | + } |
| 646 | + }) |
| 647 | + } |
| 648 | + } |
| 649 | +} |
| 650 | + |
| 569 | 651 | func TestHandlerRequestInterceptorEmptyBodyKeepsOriginalPayload(t *testing.T) { |
| 570 | 652 | model := "handler-interceptor-empty-body-model" |
| 571 | 653 | executor := &interceptorCaptureExecutor{} |