Skip to content

Commit

Permalink
Fix missing headers for fetch (#687)
Browse files Browse the repository at this point in the history
* fix: test typo

* attempt to fix #679

* export enableCapture

* fix type

* fix type for undici

* edits to package-lock.json(s)

---------

Co-authored-by: jjllee <[email protected]>
  • Loading branch information
berndfuhrmann and jj22ee authored Oct 14, 2024
1 parent 9552603 commit e28c1af
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 21 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions sdk_contrib/fetch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,4 @@ I could find that this will happen, but throwing it out there "just in case".
## Contributors

- [Jason Terando](https://github.com/jasonterando)
- [Bernd Fuhrmann](https://github.com/berndfuhrmann)
6 changes: 6 additions & 0 deletions sdk_contrib/fetch/lib/fetch_p.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ export function captureFetchModule(
subsegmentCallback?: (subsegment: AWSXRay.Subsegment, req: fetchModule.Request, res: fetchModule.Response | null, error?: Error | undefined) => void):
(url: URL | fetchModule.RequestInfo, init?: fetchModule.RequestInit | undefined) => Promise<fetchModule.Response>;

export function enableCapture<Fetch, Request>(
fetch: Fetch,
request: Request,
downstreamXRayEnabled?: boolean,
subsegmentCallback?: (subsegment: AWSXRay.Subsegment, req: Request, res: Response | null, error?: Error | undefined) => void
): Fetch;
19 changes: 15 additions & 4 deletions sdk_contrib/fetch/lib/fetch_p.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,18 @@ function captureFetchModule(module, downstreamXRayEnabled, subsegmentCallback) {
return module.default;
}

const enableCapture = function enableCapture(baseFetchFunction, requestClass, downstreamXRayEnabled, subsegmentCallback) {
/**
* Return a fetch function that will pass segment information to the target host.
* This does not change any globals
* @param {function} baseFetchFunction fetch function to use as basis
* @param {function} requestClass Request class to use. This should correspond to the supplied fetch function.
* @param {boolean} downstreamXRayEnabled - when true, adds a "traced:true" property to the subsegment
* so the AWS X-Ray service expects a corresponding segment from the downstream service.
* @param {function} subsegmentCallback - a callback that is called with the subsegment, the fetch request,
* the fetch response and any error issued, allowing custom annotations and metadata to be added.
* @returns Response
*/
function enableCapture(baseFetchFunction, requestClass, downstreamXRayEnabled, subsegmentCallback) {

const overridenFetchAsync = async (...args) => {
const thisDownstreamXRayEnabled = !!downstreamXRayEnabled;
Expand Down Expand Up @@ -116,7 +127,7 @@ const enableCapture = function enableCapture(baseFetchFunction, requestClass, do
const requestClone = request.clone();
let response;
try {
response = await baseFetchFunction(...args);
response = await baseFetchFunction(requestClone);

if (thisSubsegmentCallback) {
thisSubsegmentCallback(subsegment, requestClone, response);
Expand Down Expand Up @@ -159,8 +170,8 @@ const enableCapture = function enableCapture(baseFetchFunction, requestClass, do
};

return overridenFetchAsync;
};
}

module.exports.captureFetchGlobal = captureFetchGlobal;
module.exports.captureFetchModule = captureFetchModule;
module.exports._fetchEnableCapture = enableCapture;
module.exports.enableCapture = enableCapture;
2 changes: 1 addition & 1 deletion sdk_contrib/fetch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"repository": "https://github.com/aws/aws-xray-sdk-node/tree/master/sdk_contrib/fetch",
"devDependencies": {
"@types/node-fetch": "^2.6.4",
"chai-as-promised": "^7.1.1",
"chai-as-promised": "=7.1.1",
"node-fetch": "^2.6.11",
"ts-expect": "^1.3.0"
},
Expand Down
51 changes: 49 additions & 2 deletions sdk_contrib/fetch/test/integration/fetch_p.test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@

let listener;
let server;
let goodUrl;
let receivedHeaders;


before(() => {
// Create an HTTP server to receive requests.
const http = require('http');
server = http.createServer((req, res) => {
receivedHeaders = { ...req.headers };
// Respond with something
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Example reply\n');
});

listener = server.listen();
const address = server.address();
const host = address.family === 'IPv6' ? `[${address.address}]` : address.address;
goodUrl = `http://${host}:${address.port}/test`;
});

after(() => {
// close http server
listener.close();
});

describe('Integration tests', function () {
const chai = require('chai');
const sinonChai = require('sinon-chai');
Expand All @@ -16,12 +44,11 @@ describe('Integration tests', function () {
const fetchModule = require('node-fetch');
const Segment = AWSXray.Segment;
const Subsegment = AWSXray.Subsegment;
const goodUrl = 'https://example.org';
const badUrl = 'http://localhost:1';

const hasGlobalFetch = globalThis.fetch !== undefined;

describe('captureFetchModule', function () {
describe('captureFetchGlobal', function () {

let saveGlobalFetch;
let mockSegment;
Expand All @@ -43,6 +70,7 @@ describe('Integration tests', function () {
stubAddFetchRequestData = sandbox.stub(mockSubsegment, 'addFetchRequestData');
stubAddErrorFlag = sandbox.stub(mockSubsegment, 'addErrorFlag');
stubClose = sandbox.stub(mockSubsegment, 'close');
receivedHeaders = {};
});

afterEach(function () {
Expand All @@ -65,6 +93,24 @@ describe('Integration tests', function () {
stubClose.should.have.been.calledOnce;
});

it('adds header', async function () {
const spyCallback = sandbox.spy();
const fetch = captureFetchGlobal(true, spyCallback);
const response = await fetch(goodUrl, { headers: {
'foo': 'bar'
}});
response.status.should.equal(200);
receivedHeaders.should.to.have.property('x-amzn-trace-id');
receivedHeaders.should.to.have.property('foo', 'bar');
(await response.text()).should.contain('Example');
stubIsAutomaticMode.should.have.been.called;
stubAddNewSubsegment.should.have.been.calledOnce;
stubResolveSegment.should.have.been.calledOnce;
stubAddFetchRequestData.should.have.been.calledOnce;
stubAddErrorFlag.should.not.have.been.calledOnce;
stubClose.should.have.been.calledOnce;
});

it('sets error flag on failed fetch when global fetch exists', async function () {
const spyCallback = sandbox.spy();
const fetch = captureFetchGlobal(true, spyCallback);
Expand Down Expand Up @@ -116,6 +162,7 @@ describe('Integration tests', function () {
const fetch = captureFetchModule(fetchModule, true, spyCallback);
const response = await fetch(goodUrl);
response.status.should.equal(200);
receivedHeaders.should.to.have.property('x-amzn-trace-id');
(await response.text()).should.contain('Example');
stubIsAutomaticMode.should.have.been.called;
stubAddNewSubsegment.should.have.been.calledOnce;
Expand Down
11 changes: 0 additions & 11 deletions sdk_contrib/fetch/test/unit/fetch_p.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,17 +339,6 @@ describe('Unit tests', function () {
response.should.equal(stubValidResponse);
});

it('resolves to response through proxy when fetch options are supplied', async function() {
const activeFetch = captureFetch(true);
const proxyStub = sinon.stub();
const request = new FetchRequest('https://www.foo.com/test');
const response = await activeFetch(request, {
dispatcher: proxyStub
});
stubFetch.should.have.been.calledOnceWith(request, {dispatcher: proxyStub});
response.should.equal(stubValidResponse);
});

it('calls subsegmentCallback with error upon fetch throwing', async function () {
const spyCallback = sandbox.spy();
const activeFetch = captureFetch(true, spyCallback);
Expand Down

0 comments on commit e28c1af

Please sign in to comment.