Skip to main content

pkg/gateway/proxy/testdata/sse_server.go

Source

Overview

What: Test-only upstream handler that emits Server-Sent Events (SSE).

Why:

SSE is a long-lived streaming protocol that depends on:

  • correct text/event-stream content type
  • periodic flushes
  • request cancellation propagation

This handler exists so proxy tests can validate that the gateway forwards SSE streams correctly without buffering and without requiring an external upstream.

How:

NewSSEServer() returns an http.Handler that:

  • validates flush support
  • sets standard SSE response headers
  • emits a small JSON payload every tick using the SSE wire format
  • flushes each event
  • stops after a small number of messages (or when the client cancels)

Notes:

The handler uses math/rand to vary a small hint field. The randomness is not used for assertions; it simply ensures the payload is not constant and exercises JSON encoding.

Contents

Imports

import block 1

pkg/gateway/proxy/testdata/sse_server.go#L3
import (
"encoding/json"
"fmt"
"math/rand"
"net/http"
"time"
)

Functions and Methods

NewSSEServer

What: Constructs an SSE handler suitable for proxy streaming tests.

Why: Provides a deterministic, local SSE upstream to exercise the gateway's proxying of event streams.

How: Returns an http.HandlerFunc that writes SSE frames (id, event, data) on a timer, flushing after each frame and stopping after a small number of events.

Notes: SSE requires http.Flusher; the handler returns 500 if flushing is unsupported.

pkg/gateway/proxy/testdata/sse_server.go#L12
func NewSSEServer() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
flusher, ok := w.(http.Flusher)
if !ok {
http.Error(w, "streaming unsupported", http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")

ticker := time.NewTicker(50 * time.Millisecond)
defer ticker.Stop()

type payload struct {
ID int `json:"id"`
Hint string `json:"hint"`
}

sent := 0
for {
select {
case <-r.Context().Done():
return
case <-ticker.C:
sent++
message := payload{ID: sent, Hint: fmt.Sprintf("seed-%d", rand.Intn(100))}
data, _ := json.Marshal(message)
fmt.Fprintf(w, "id: %d\nevent: tick\ndata: %s\n\n", sent, data)
flusher.Flush()
if sent >= 5 {
return
}
}
}
})
}

Walkthrough

The list below documents the statements inside the function body, including nested blocks and inline closures.

  • L13: return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "streaming un…
    • What: Returns from the current function.
    • Why: Ends the current execution path and hands control back to the caller.
    • How: Executes a return statement (possibly returning values).
    • Nested steps:
      • L13: func(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "streaming unsupported", http.StatusI…
        • What: Defines an inline function (closure).
        • Why: Encapsulates callback logic and may capture variables from the surrounding scope.
        • How: Declares a func literal and uses it as a value (for example, as an HTTP handler or callback).
        • Nested steps:
          • L14: flusher, ok := w.(http.Flusher)
            • What: Defines flusher, ok.
            • Why: Keeps intermediate state available for later steps in the function.
            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
          • L15: if !ok { http.Error(w, "streaming unsupported", http.StatusInternalServerError) return }
            • What: Branches conditionally.
            • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
            • How: Evaluates the condition and executes the matching branch.
            • Nested steps:
              • L16: http.Error(w, "streaming unsupported", http.StatusInternalServerError)
                • What: Calls http.Error.
                • Why: Performs side effects or delegates work to a helper.
                • How: Executes the expression statement.
              • L17: return
                • What: Returns from the current function.
                • Why: Ends the current execution path and hands control back to the caller.
                • How: Executes a return statement (possibly returning values).
          • L20: w.Header().Set("Content-Type", "text/event-stream")
            • What: Calls w.Header().Set.
            • Why: Performs side effects or delegates work to a helper.
            • How: Executes the expression statement.
          • L21: w.Header().Set("Cache-Control", "no-cache")
            • What: Calls w.Header().Set.
            • Why: Performs side effects or delegates work to a helper.
            • How: Executes the expression statement.
          • L22: w.Header().Set("Connection", "keep-alive")
            • What: Calls w.Header().Set.
            • Why: Performs side effects or delegates work to a helper.
            • How: Executes the expression statement.
          • L24: ticker := time.NewTicker(50 * time.Millisecond)
            • What: Defines ticker.
            • Why: Keeps intermediate state available for later steps in the function.
            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
          • L25: defer ticker.Stop()
            • What: Defers a call for cleanup.
            • Why: Ensures the deferred action runs even on early returns.
            • How: Schedules the call to run when the surrounding function returns.
          • L27: type payload struct { ID int `json:"id"` Hint string `json:"hint"` }
            • What: Declares local names.
            • Why: Introduces variables or types used later in the function.
            • How: Executes a Go declaration statement inside the function body.
          • L32: sent := 0
            • What: Defines sent.
            • Why: Keeps intermediate state available for later steps in the function.
            • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
          • L33: for { select { case <-r.Context().Done(): return case <-ticker.C: sent++ message := payload{ID: sent, Hint: fmt.Sprintf("seed-%d", rand.Int…
            • What: Runs a loop.
            • Why: Repeats logic until a condition is met or the loop terminates.
            • How: Executes a for loop statement.
            • Nested steps:
              • L34: select { case <-r.Context().Done(): return case <-ticker.C: sent++ message := payload{ID: sent, Hint: fmt.Sprintf("seed-%d", rand.Intn(100)…
                • What: Selects among concurrent operations.
                • Why: Coordinates channel operations without blocking incorrectly.
                • How: Executes a select statement and runs one ready case.
                • Nested steps:
                  • L35: case <-r.Context().Done():
                    • What: Selects a select-case branch.
                    • Why: Coordinates concurrent operations without blocking incorrectly.
                    • How: Runs this case body when its channel operation is ready (or runs default immediately).
                    • Nested steps:
                      • L36: return
                        • What: Returns from the current function.
                        • Why: Ends the current execution path and hands control back to the caller.
                        • How: Executes a return statement (possibly returning values).
                  • L37: case <-ticker.C:
                    • What: Selects a select-case branch.
                    • Why: Coordinates concurrent operations without blocking incorrectly.
                    • How: Runs this case body when its channel operation is ready (or runs default immediately).
                    • Nested steps:
                      • L38: sent++
                        • What: Updates a counter.
                        • Why: Maintains an index or tally used by subsequent logic.
                        • How: Executes an increment/decrement statement.
                      • L39: message := payload{ID: sent, Hint: fmt.Sprintf("seed-%d", rand.Intn(100))}
                        • What: Defines message.
                        • Why: Keeps intermediate state available for later steps in the function.
                        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                      • L40: data, _ := json.Marshal(message)
                        • What: Defines data, _.
                        • Why: Keeps intermediate state available for later steps in the function.
                        • How: Evaluates the right-hand side expressions and stores results in the left-hand variables.
                      • L41: fmt.Fprintf(w, "id: %d\nevent: tick\ndata: %s\n\n", sent, data)
                        • What: Calls fmt.Fprintf.
                        • Why: Performs side effects or delegates work to a helper.
                        • How: Executes the expression statement.
                      • L42: flusher.Flush()
                        • What: Calls flusher.Flush.
                        • Why: Performs side effects or delegates work to a helper.
                        • How: Executes the expression statement.
                      • L43: if sent >= 5 { return }
                        • What: Branches conditionally.
                        • Why: Short-circuits early when a precondition is not met or an error/edge case is detected.
                        • How: Evaluates the condition and executes the matching branch.
                        • Nested steps:
                          • L44: return
                            • What: Returns from the current function.
                            • Why: Ends the current execution path and hands control back to the caller.
                            • How: Executes a return statement (possibly returning values).

Architecture

Guides

Neighboring source