diff --git a/packages/ec2-metadata-service/src/MetadataService.spec.ts b/packages/ec2-metadata-service/src/MetadataService.spec.ts index 3048fceb905b..1b963ea2950d 100644 --- a/packages/ec2-metadata-service/src/MetadataService.spec.ts +++ b/packages/ec2-metadata-service/src/MetadataService.spec.ts @@ -253,3 +253,76 @@ describe("MetadataService Socket Leak Checks", () => { }); }); }); + +describe("MetadataService Custom Ports", () => { + let metadataService: MetadataService; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + const createMockResponse = (statusCode: number, body: string) => { + const stream = Readable.from([body]); + return { + response: { + statusCode, + body: stream, + headers: {}, + }, + }; + }; + + it("should use custom port from endpoint URL in request()", async () => { + metadataService = new MetadataService({ + endpoint: "http://localhost:1338", + httpOptions: { timeout: 1000 }, + }); + + const mockResponse = createMockResponse(200, "i-1234567890abcdef0"); + const mockHandle = vi.fn().mockResolvedValue(mockResponse); + + vi.mocked(NodeHttpHandler).mockImplementation(() => ({ handle: mockHandle } as any)); + + await metadataService.request("/latest/meta-data/instance-id", {}); + + const requestArg = mockHandle.mock.calls[0][0]; + expect(requestArg.port).toBe(1338); + expect(requestArg.hostname).toBe("localhost"); + }); + + it("should use custom port from endpoint URL in fetchMetadataToken()", async () => { + metadataService = new MetadataService({ + endpoint: "http://localhost:1338", + httpOptions: { timeout: 1000 }, + }); + + const mockResponse = createMockResponse(200, "test-token-123"); + const mockHandle = vi.fn().mockResolvedValue(mockResponse); + + vi.mocked(NodeHttpHandler).mockImplementation(() => ({ handle: mockHandle } as any)); + + await metadataService.fetchMetadataToken(); + + const requestArg = mockHandle.mock.calls[0][0]; + expect(requestArg.port).toBe(1338); + expect(requestArg.hostname).toBe("localhost"); + }); + + it("should use undefined port for standard HTTP endpoint", async () => { + metadataService = new MetadataService({ + endpoint: "http://169.254.169.254", + httpOptions: { timeout: 1000 }, + }); + + const mockResponse = createMockResponse(200, "test-token-123"); + const mockHandle = vi.fn().mockResolvedValue(mockResponse); + + vi.mocked(NodeHttpHandler).mockImplementation(() => ({ handle: mockHandle } as any)); + + await metadataService.fetchMetadataToken(); + + const requestArg = mockHandle.mock.calls[0][0]; + expect(requestArg.port).toBeUndefined(); + expect(requestArg.hostname).toBe("169.254.169.254"); + }); +}); diff --git a/packages/ec2-metadata-service/src/MetadataService.ts b/packages/ec2-metadata-service/src/MetadataService.ts index ca27dcf2a162..14e2bdb63aa9 100644 --- a/packages/ec2-metadata-service/src/MetadataService.ts +++ b/packages/ec2-metadata-service/src/MetadataService.ts @@ -69,6 +69,7 @@ export class MetadataService { hostname: endpointUrl.hostname, path: endpointUrl.pathname + path, protocol: endpointUrl.protocol, + port: endpointUrl.port ? parseInt(endpointUrl.port) : undefined, }); try { const { response } = await handler.handle(request, {} as HttpHandlerOptions); @@ -102,6 +103,7 @@ export class MetadataService { hostname: endpointUrl.hostname, path: "/latest/api/token", protocol: endpointUrl.protocol, + port: endpointUrl.port ? parseInt(endpointUrl.port) : undefined, }); try { const { response } = await handler.handle(tokenRequest, {} as HttpHandlerOptions);