Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Commit 9235b50

Browse files
vmarchaudmayurkale22
authored andcommitted
http-instrumentation: fix propagation errors when using Expect header #481 (#482)
* http-instrumentation: fix propagation errors when using Expect header #481 * chore: more details for the Expect header logic * chore: address PR comments
1 parent f0cb7e9 commit 9235b50

2 files changed

Lines changed: 47 additions & 1 deletion

File tree

packages/opencensus-instrumentation-http/src/http.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,12 +360,28 @@ export class HttpPlugin extends BasePlugin {
360360

361361
const setter: HeaderSetter = {
362362
setHeader(name: string, value: string) {
363-
request.setHeader(name, value);
363+
// If outgoing request headers contain the "Expect" header, the
364+
// returned ClientRequest will throw an error if any new headers are
365+
// added. We need to set the header directly in the headers object
366+
// which has been cloned earlier.
367+
if (plugin.hasExpectHeader(options) && options.headers) {
368+
options.headers[name] = value;
369+
} else {
370+
request.setHeader(name, value);
371+
}
364372
}
365373
};
366374

367375
const propagation = plugin.tracer.propagation;
368376
if (propagation) {
377+
// If outgoing request headers contain the "Expect" header, the returned
378+
// ClientRequest will throw an error if any new headers are added.
379+
// So we need to clone the options object to be able to inject new
380+
// header.
381+
if (plugin.hasExpectHeader(options)) {
382+
options = Object.assign({}, options) as RequestOptions;
383+
options.headers = Object.assign({}, options.headers);
384+
}
369385
propagation.inject(setter, span.spanContext);
370386
}
371387

@@ -485,6 +501,16 @@ export class HttpPlugin extends BasePlugin {
485501
} catch (ignore) {
486502
}
487503
}
504+
505+
/**
506+
* Returns whether the Expect header is on the given options object.
507+
* @param options Options for http.request.
508+
*/
509+
hasExpectHeader(options: RequestOptions|url.URL): boolean {
510+
return !!(
511+
(options as RequestOptions).headers &&
512+
(options as RequestOptions).headers!.Expect);
513+
}
488514
}
489515

490516
const plugin = new HttpPlugin('http');

packages/opencensus-instrumentation-http/test/test-http.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import * as assert from 'assert';
1919
import * as http from 'http';
2020
import * as nock from 'nock';
2121
import * as shimmer from 'shimmer';
22+
import * as url from 'url';
2223

2324
import {HttpPlugin, plugin} from '../src/';
2425
import * as stats from '../src/http-stats';
@@ -374,6 +375,25 @@ describe('HttpPlugin', () => {
374375
});
375376
nock.disableNetConnect();
376377
});
378+
379+
it('should create a rootSpan for GET requests and add propagation headers with Expect headers',
380+
async () => {
381+
nock.enableNetConnect();
382+
assert.strictEqual(rootSpanVerifier.endedRootSpans.length, 0);
383+
const options = Object.assign(
384+
{headers: {Expect: '100-continue'}},
385+
url.parse('http://google.fr/'));
386+
await httpRequest.get(options).then((result) => {
387+
assert.strictEqual(rootSpanVerifier.endedRootSpans.length, 1);
388+
assert.ok(
389+
rootSpanVerifier.endedRootSpans[0].name.indexOf('GET /') >= 0);
390+
391+
const span = rootSpanVerifier.endedRootSpans[0];
392+
assertSpanAttributes(span, 301, 'GET', 'google.fr', '/');
393+
assertClientStats(testExporter, 301, 'GET');
394+
});
395+
nock.disableNetConnect();
396+
});
377397
});
378398

379399

0 commit comments

Comments
 (0)