Skip to content

Commit

Permalink
fix(middleware-user-agent-header): swap user agent headers for non-br…
Browse files Browse the repository at this point in the history
…owser environments (#2313)
  • Loading branch information
trivikr committed Apr 29, 2021
1 parent 60a4215 commit d8c1dc2
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 47 deletions.
95 changes: 51 additions & 44 deletions packages/middleware-user-agent/src/user-agent-middleware.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,40 @@ describe("userAgentMiddleware", () => {
jest.clearAllMocks();
});

it("should collect user agent pair from default, custom-supplied, and handler context", async () => {
const middleware = userAgentMiddleware({
defaultUserAgentProvider: async () => [
["default_agent", "1.0.0"],
["aws-sdk-js", "1.0.0"],
],
customUserAgent: [["custom_ua/abc"]],
runtime: "node",
});
const handler = middleware(mockNextHandler, { userAgent: [["cfg/retry-mode", "standard"]] });
await handler({ input: {}, request: new HttpRequest({ headers: {} }) });
expect(mockNextHandler.mock.calls.length).toEqual(1);
const sdkUserAgent = mockNextHandler.mock.calls[0][0].request.headers[X_AMZ_USER_AGENT];
expect(sdkUserAgent).toEqual(expect.stringContaining("aws-sdk-js/1.0.0"));
expect(sdkUserAgent).toEqual(expect.stringContaining("default_agent/1.0.0"));
expect(sdkUserAgent).toEqual(expect.stringContaining("custom_ua/abc"));
expect(sdkUserAgent).toEqual(expect.stringContaining("cfg/retry-mode/standard"));
expect(mockNextHandler.mock.calls[0][0].request.headers[USER_AGENT]).toEqual(
expect.stringContaining("aws-sdk-js/1.0.0")
describe("should collect user agent pair from default, custom-supplied, and handler context", () => {
[
{ runtime: "node", sdkUserAgentKey: USER_AGENT, userAgentKey: X_AMZ_USER_AGENT },
{ runtime: "browser", sdkUserAgentKey: X_AMZ_USER_AGENT, userAgentKey: USER_AGENT },
].forEach(({ runtime, sdkUserAgentKey, userAgentKey }) =>
it(runtime, async () => {
const middleware = userAgentMiddleware({
defaultUserAgentProvider: async () => [
["default_agent", "1.0.0"],
["aws-sdk-js", "1.0.0"],
],
customUserAgent: [["custom_ua/abc"]],
runtime,
});
const handler = middleware(mockNextHandler, { userAgent: [["cfg/retry-mode", "standard"]] });
await handler({ input: {}, request: new HttpRequest({ headers: {} }) });
expect(mockNextHandler.mock.calls.length).toEqual(1);
const sdkUserAgent = mockNextHandler.mock.calls[0][0].request.headers[sdkUserAgentKey];
expect(sdkUserAgent).toEqual(expect.stringContaining("aws-sdk-js/1.0.0"));
expect(sdkUserAgent).toEqual(expect.stringContaining("default_agent/1.0.0"));
expect(sdkUserAgent).toEqual(expect.stringContaining("custom_ua/abc"));
expect(sdkUserAgent).toEqual(expect.stringContaining("cfg/retry-mode/standard"));
if (userAgentKey === USER_AGENT) {
expect(mockNextHandler.mock.calls[0][0].request.headers[userAgentKey]).toBeUndefined();
} else {
expect(mockNextHandler.mock.calls[0][0].request.headers[userAgentKey]).toEqual(
expect.stringContaining("aws-sdk-js/1.0.0")
);
}
})
);
});

it(`should not set ${USER_AGENT} header in browser`, async () => {
const middleware = userAgentMiddleware({
defaultUserAgentProvider: async () => [["aws-sdk-js", "1.0.0"]],
runtime: "browser",
});
const handler = middleware(mockNextHandler, {});
await handler({ input: {}, request: new HttpRequest({ headers: {} }) });
expect(mockNextHandler.mock.calls.length).toEqual(1);
expect(mockNextHandler.mock.calls[0][0].request.headers[USER_AGENT]).toBeUndefined();
});

describe("should sanitize the user agent string", () => {
describe("should sanitize the SDK user agent string", () => {
const cases: { ua: UserAgentPair; expected: string }[] = [
{ ua: ["/name", "1.0.0"], expected: "name/1.0.0" },
{ ua: ["Name", "1.0.0"], expected: "Name/1.0.0" },
Expand All @@ -54,18 +54,25 @@ describe("userAgentMiddleware", () => {
{ ua: ["name", "1.0.0(test_version)"], expected: "name/1.0.0_test_version" },
{ ua: ["api/Service", "1.0.0"], expected: "api/service/1.0.0" },
];
for (const { ua, expected } of cases) {
it(`should sanitize user agent ${ua} to ${expected}`, async () => {
const middleware = userAgentMiddleware({
defaultUserAgentProvider: async () => [ua],
runtime: "browser",
});
const handler = middleware(mockNextHandler, {});
await handler({ input: {}, request: new HttpRequest({ headers: {} }) });
expect(mockNextHandler.mock.calls[0][0].request.headers[X_AMZ_USER_AGENT]).toEqual(
expect.stringContaining(expected)
);
});
}
[
{ runtime: "node", sdkUserAgentKey: USER_AGENT },
{ runtime: "browser", sdkUserAgentKey: X_AMZ_USER_AGENT },
].forEach(({ runtime, sdkUserAgentKey }) =>
describe(runtime, () => {
for (const { ua, expected } of cases) {
it(`should sanitize user agent ${ua} to ${expected}`, async () => {
const middleware = userAgentMiddleware({
defaultUserAgentProvider: async () => [ua],
runtime,
});
const handler = middleware(mockNextHandler, {});
await handler({ input: {}, request: new HttpRequest({ headers: {} }) });
expect(mockNextHandler.mock.calls[0][0].request.headers[sdkUserAgentKey]).toEqual(
expect.stringContaining(expected)
);
});
}
})
);
});
});
13 changes: 10 additions & 3 deletions packages/middleware-user-agent/src/user-agent-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,22 @@ export const userAgentMiddleware = (options: UserAgentResolvedConfig) => <Output
const userAgent = context?.userAgent?.map(escapeUserAgent) || [];
const defaultUserAgent = (await options.defaultUserAgentProvider()).map(escapeUserAgent);
const customUserAgent = options?.customUserAgent?.map(escapeUserAgent) || [];

// Set value to AWS-specific user agent header
headers[X_AMZ_USER_AGENT] = [...defaultUserAgent, ...userAgent, ...customUserAgent].join(SPACE);
const sdkUserAgentValue = [...defaultUserAgent, ...userAgent, ...customUserAgent].join(SPACE);
// Get value to be sent with non-AWS-specific user agent header.
const normalUAValue = [
...defaultUserAgent.filter((section) => section.startsWith("aws-sdk-")),
...customUserAgent,
].join(SPACE);
if (options.runtime !== "browser" && normalUAValue) {
headers[USER_AGENT] = headers[USER_AGENT] ? `${headers[USER_AGENT]} ${normalUAValue}` : normalUAValue;

if (options.runtime !== "browser") {
if (normalUAValue) {
headers[X_AMZ_USER_AGENT] = headers[X_AMZ_USER_AGENT] ? `${headers[USER_AGENT]} ${normalUAValue}` : normalUAValue;
}
headers[USER_AGENT] = sdkUserAgentValue;
} else {
headers[X_AMZ_USER_AGENT] = sdkUserAgentValue;
}

return next({
Expand Down

0 comments on commit d8c1dc2

Please sign in to comment.