|
5 | 5 | "errors" |
6 | 6 | "io" |
7 | 7 | "net/http" |
| 8 | + "net/http/httptest" |
| 9 | + "strings" |
8 | 10 | "testing" |
9 | 11 | "time" |
10 | 12 |
|
@@ -170,6 +172,71 @@ func TestPostRPCStreamContextCanceled(t *testing.T) { |
170 | 172 | } |
171 | 173 | } |
172 | 174 |
|
| 175 | +// TestRequestInfoRefs_FollowInfoRefsRedirect verifies that when the flag is |
| 176 | +// set, a 307 on /info/refs rewrites Conn.Endpoint.Host so subsequent PostRPC |
| 177 | +// calls target the redirected node. Matches vanilla git's smart-HTTP |
| 178 | +// behaviour and lets clients use a cluster entry domain for info/refs while |
| 179 | +// packs land on the hosting replica. |
| 180 | +func TestRequestInfoRefs_FollowInfoRefsRedirect(t *testing.T) { |
| 181 | + node := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 182 | + w.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement") |
| 183 | + _, _ = w.Write([]byte("001e# service=git-upload-pack\n0000")) |
| 184 | + })) |
| 185 | + defer node.Close() |
| 186 | + |
| 187 | + entry := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 188 | + http.Redirect(w, r, node.URL+r.URL.Path+"?"+r.URL.RawQuery, http.StatusTemporaryRedirect) |
| 189 | + })) |
| 190 | + defer entry.Close() |
| 191 | + |
| 192 | + ep, err := transport.NewEndpoint(entry.URL + "/repo.git") |
| 193 | + if err != nil { |
| 194 | + t.Fatalf("parse endpoint: %v", err) |
| 195 | + } |
| 196 | + conn := NewConn(ep, "test", nil, http.DefaultTransport) |
| 197 | + conn.FollowInfoRefsRedirect = true |
| 198 | + |
| 199 | + if _, err := RequestInfoRefs(t.Context(), conn, transport.UploadPackService, ""); err != nil { |
| 200 | + t.Fatalf("RequestInfoRefs: %v", err) |
| 201 | + } |
| 202 | + |
| 203 | + nodeURL := strings.TrimPrefix(node.URL, "http://") |
| 204 | + if conn.Endpoint.Host != nodeURL { |
| 205 | + t.Errorf("Endpoint.Host = %q, want %q (endpoint should follow the 307)", conn.Endpoint.Host, nodeURL) |
| 206 | + } |
| 207 | +} |
| 208 | + |
| 209 | +// TestRequestInfoRefs_DoesNotFollowByDefault confirms the default behaviour |
| 210 | +// is unchanged: Endpoint is stable even if the server 307s. |
| 211 | +func TestRequestInfoRefs_DoesNotFollowByDefault(t *testing.T) { |
| 212 | + node := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 213 | + w.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement") |
| 214 | + _, _ = w.Write([]byte("001e# service=git-upload-pack\n0000")) |
| 215 | + })) |
| 216 | + defer node.Close() |
| 217 | + |
| 218 | + entry := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 219 | + http.Redirect(w, r, node.URL+r.URL.Path+"?"+r.URL.RawQuery, http.StatusTemporaryRedirect) |
| 220 | + })) |
| 221 | + defer entry.Close() |
| 222 | + |
| 223 | + ep, err := transport.NewEndpoint(entry.URL + "/repo.git") |
| 224 | + if err != nil { |
| 225 | + t.Fatalf("parse endpoint: %v", err) |
| 226 | + } |
| 227 | + entryHost := ep.Host |
| 228 | + conn := NewConn(ep, "test", nil, http.DefaultTransport) |
| 229 | + // FollowInfoRefsRedirect intentionally not set. |
| 230 | + |
| 231 | + if _, err := RequestInfoRefs(t.Context(), conn, transport.UploadPackService, ""); err != nil { |
| 232 | + t.Fatalf("RequestInfoRefs: %v", err) |
| 233 | + } |
| 234 | + |
| 235 | + if conn.Endpoint.Host != entryHost { |
| 236 | + t.Errorf("Endpoint.Host = %q, want %q (endpoint should be unchanged by default)", conn.Endpoint.Host, entryHost) |
| 237 | + } |
| 238 | +} |
| 239 | + |
173 | 240 | func TestHTTPErrorBoundsBodyRead(t *testing.T) { |
174 | 241 | req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "https://example.com/repo.git", nil) |
175 | 242 | if err != nil { |
|
0 commit comments