Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ For notes on migrating to 2.x / 0.200.x see [the upgrade guide](doc/upgrade-to-2
* test(sdk-node): use process.env consistently in tests [#6052](https://github.com/open-telemetry/opentelemetry-js/pull/6052) @cjihrig
* test(sdk-node): ensure process.env is cleaned up between tests [#6066](https://github.com/open-telemetry/opentelemetry-js/pull/6066) @cjihrig
* refactor(instrumentation-http): avoid deprecated url.parse() in getAbsoluteUrl() [#6089](https://github.com/open-telemetry/opentelemetry-js/pull/6089) @cjihrig
* test(instrumentation-http): avoid deprecated url.parse() [#xxxx](https://github.com/open-telemetry/opentelemetry-js/pull/xxxx) @cjihrig
Comment thread
cjihrig marked this conversation as resolved.
Outdated

## 0.207.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
} from '@opentelemetry/sdk-trace-base';
import * as assert from 'assert';
import * as path from 'path';
import * as url from 'url';
import { HttpInstrumentation } from '../../src/http';
import { assertSpan } from '../utils/assertSpan';
import { DummyPropagation } from '../utils/DummyPropagation';
Expand Down Expand Up @@ -83,22 +82,22 @@ describe('Packages', () => {
it(`should create a span for GET requests and add propagation headers by using ${name} package`, async () => {
nock.load(path.join(__dirname, '../', '/fixtures/google-http.json'));

const urlparsed = url.parse(
const urlparsed = new URL(
`${protocol}://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8`
);
const result = await httpPackage.get(urlparsed.href!);
const result = await httpPackage.get(urlparsed.href);
if (!resHeaders) {
const res = result as axios.AxiosResponse<unknown>;
resHeaders = res.headers as any;
}
const spans = memoryExporter.getFinishedSpans();
const span = spans[0];
const validations = {
hostname: urlparsed.hostname!,
hostname: urlparsed.hostname,
httpStatusCode: 200,
httpMethod: 'GET',
pathname: urlparsed.pathname!,
path: urlparsed.path,
pathname: urlparsed.pathname,
path: urlparsed.pathname + urlparsed.search,
resHeaders,
component: 'http',
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
} from '@opentelemetry/sdk-trace-base';
import * as assert from 'assert';
import * as path from 'path';
import * as url from 'url';
import { HttpInstrumentation } from '../../src/http';
import { assertSpan } from '../utils/assertSpan';
import { DummyPropagation } from '../utils/DummyPropagation';
Expand Down Expand Up @@ -83,22 +82,22 @@ describe('Packages', () => {
it(`should create a span for GET requests and add propagation headers by using ${name} package`, async () => {
nock.load(path.join(__dirname, '../', '/fixtures/google-https.json'));

const urlparsed = url.parse(
const urlparsed = new URL(
'https://www.google.com/search?q=axios&oq=axios&aqs=chrome.0.69i59l2j0l3j69i60.811j0j7&sourceid=chrome&ie=UTF-8'
);
const result = await httpPackage.get(urlparsed.href!);
const result = await httpPackage.get(urlparsed.href);
if (!resHeaders) {
const res = result as axios.AxiosResponse<unknown>;
resHeaders = res.headers as any;
}
const spans = memoryExporter.getFinishedSpans();
const span = spans[0];
const validations = {
hostname: urlparsed.hostname!,
hostname: urlparsed.hostname,
httpStatusCode: 200,
httpMethod: 'GET',
pathname: urlparsed.pathname!,
path: urlparsed.path,
pathname: urlparsed.pathname,
path: urlparsed.pathname + urlparsed.search,
resHeaders,
component: 'https',
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks';
import { SemconvStability } from '@opentelemetry/instrumentation';
import { extractHostnameAndPort } from '../../src/utils';
import { AttributeNames } from '../../src/enums/AttributeNames';
import { ParsedUrlQuery } from 'node:querystring';

describe('Utility', () => {
describe('parseResponseStatus()', () => {
Expand Down Expand Up @@ -80,7 +81,20 @@ describe('Utility', () => {
describe('getRequestInfo()', () => {
it('should get options object', () => {
const webUrl = 'http://u:p@google.fr/aPath?qu=ry';
const urlParsed = url.parse(webUrl);
const urlParsed = {
protocol: 'http:',
slashes: true,
auth: 'u:p',
host: 'google.fr',
port: null,
hostname: 'google.fr',
hash: null,
search: '?qu=ry',
query: 'qu=ry',
pathname: '/aPath',
path: '/aPath?qu=ry',
href: 'http://u:p@google.fr/aPath?qu=ry',
};
const urlParsedWithoutPathname = {
...urlParsed,
pathname: undefined,
Expand All @@ -95,7 +109,7 @@ describe('Utility', () => {
host: undefined,
port: null,
};
const whatWgUrl = new url.URL(webUrl);
const whatWgUrl = new URL(webUrl);
for (const param of [
webUrl,
urlParsed,
Expand Down Expand Up @@ -155,12 +169,44 @@ describe('Utility', () => {
describe('getAbsoluteUrl()', () => {
it('should return absolute url with localhost', () => {
const path = '/test/1';
const result = utils.getAbsoluteUrl(url.parse(path), {});
const result = utils.getAbsoluteUrl(
{
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: null,
query: null as unknown as undefined,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated note - the types for getAbsoluteUrl() seem like they may be slightly incorrect. See the other type cast on line 203 of this file.

url.parse() returns an object whose query field is of type string | null | ParsedUrlQuery. However, string and null are problematic in getAbsoluteUrl(). The first argument to getAbsoluteUrl() is currently ParsedRequestOptions | null. ParsedRequestOptions is defined as:

export type ParsedRequestOptions =
  | (http.RequestOptions & Partial<url.UrlWithParsedQuery>)
  | http.RequestOptions;

And, the relevant Node core types are:

    // Output of `url.parse`
    interface Url {
        auth: string | null;
        hash: string | null;
        host: string | null;
        hostname: string | null;
        href: string;
        path: string | null;
        pathname: string | null;
        protocol: string | null;
        search: string | null;
        slashes: boolean | null;
        port: string | null;
        query: string | null | ParsedUrlQuery;
    }
    interface UrlWithParsedQuery extends Url {
        query: ParsedUrlQuery;
    }
    interface UrlWithStringQuery extends Url {
        query: string | null;
    }

It's not clear to me why ParsedRequestOptions uses url.UrlWithParsedQuery instead of url.Url here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tired to do some archeology on this and it seems that this was added all the way back in #161 and has grown to be somewhat different since then. I think some cleanup is needed here (in a separate PR).

pathname: '/test/1',
path: '/test/1',
href: '/test/1',
},
{}
);
assert.strictEqual(result, `http://localhost${path}`);
});
it('should return absolute url', () => {
const absUrl = 'http://www.google/test/1?query=1';
const result = utils.getAbsoluteUrl(url.parse(absUrl), {});
const result = utils.getAbsoluteUrl(
{
protocol: 'http:',
slashes: true,
auth: null,
host: 'www.google',
port: null,
hostname: 'www.google',
hash: null,
search: '?query=1',
query: 'query=1' as unknown as ParsedUrlQuery,
pathname: '/test/1',
path: '/test/1?query=1',
href: 'http://www.google/test/1?query=1',
},
{}
);
assert.strictEqual(result, absUrl);
});
it('should return default url', () => {
Expand Down Expand Up @@ -258,7 +304,11 @@ describe('Utility', () => {
assert.strictEqual(utils.isValidOptionsType(options), false);
});
});
for (const options of ['url', url.parse('http://url.com'), {}]) {
for (const options of [
'url',
url.urlToHttpOptions(new URL('http://url.com')),
{},
]) {
it(`should return true with the following value: ${JSON.stringify(
options
)}`, () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
NET_TRANSPORT_VALUE_IP_TCP,
} from '../../src/semconv';
import * as assert from 'assert';
import * as url from 'url';
import { urlToHttpOptions } from 'url';
import { HttpInstrumentation } from '../../src/http';
import { assertSpan } from '../utils/assertSpan';
import * as utils from '../utils/utils';
Expand Down Expand Up @@ -180,7 +180,7 @@ describe('HttpInstrumentation Integration tests', () => {
assert.strictEqual(spans.length, 0);

const result = await httpRequest.get(
new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`)
new URL(`${protocol}://localhost:${mockServerPort}/?query=test`)
);

spans = memoryExporter.getFinishedSpans();
Expand All @@ -207,7 +207,7 @@ describe('HttpInstrumentation Integration tests', () => {
assert.strictEqual(spans.length, 0);

const result = await httpRequest.get(
new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`),
new URL(`${protocol}://localhost:${mockServerPort}/?query=test`),
{
headers: { 'x-foo': 'foo' },
}
Expand Down Expand Up @@ -270,7 +270,7 @@ describe('HttpInstrumentation Integration tests', () => {

const headers = { 'x-foo': 'foo' };
const result = await httpRequest.get(
new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`),
new URL(`${protocol}://localhost:${mockServerPort}/?query=test`),
{ headers }
);
assert.deepStrictEqual(headers, { 'x-foo': 'foo' });
Expand All @@ -284,7 +284,7 @@ describe('HttpInstrumentation Integration tests', () => {

const headers = { 'x-foo': 'foo', forwarded: 'malformed' };
const result = await httpRequest.get(
new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`),
new URL(`${protocol}://localhost:${mockServerPort}/?query=test`),
{ headers }
);

Expand All @@ -297,7 +297,7 @@ describe('HttpInstrumentation Integration tests', () => {
assert.strictEqual(spans.length, 0);
const options = Object.assign(
{ headers: { Expect: '100-continue' } },
url.parse(`${protocol}://localhost:${mockServerPort}/`)
urlToHttpOptions(new URL(`${protocol}://localhost:${mockServerPort}/`))
);

const result = await httpRequest.get(options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import * as fs from 'fs';
import * as path from 'path';
import { Socket } from 'net';
import { assertSpan } from '../utils/assertSpan';
import * as url from 'url';
import { urlToHttpOptions } from 'url';
import * as utils from '../utils/utils';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import {
Expand Down Expand Up @@ -182,7 +182,7 @@ describe('HttpsInstrumentation Integration tests', () => {
assert.strictEqual(spans.length, 0);

const result = await httpsRequest.get(
new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`)
new URL(`${protocol}://localhost:${mockServerPort}/?query=test`)
);

spans = memoryExporter.getFinishedSpans();
Expand All @@ -209,7 +209,7 @@ describe('HttpsInstrumentation Integration tests', () => {
assert.strictEqual(spans.length, 0);

const result = await httpsRequest.get(
new url.URL(`${protocol}://localhost:${mockServerPort}/?query=test`),
new URL(`${protocol}://localhost:${mockServerPort}/?query=test`),
{
headers: { 'x-foo': 'foo' },
}
Expand Down Expand Up @@ -271,7 +271,7 @@ describe('HttpsInstrumentation Integration tests', () => {
assert.strictEqual(spans.length, 0);
const options = Object.assign(
{ headers: { Expect: '100-continue' } },
url.parse(`${protocol}://localhost:${mockServerPort}/`)
urlToHttpOptions(new URL(`${protocol}://localhost:${mockServerPort}/`))
);

const result = await httpsRequest.get(options);
Expand Down