Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 7 additions & 0 deletions agent/src/Envelope.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ static function (EnvelopeItem $item) use ($callback) {
);
}

public function appendIngestPath(string $version): void
{
foreach ($this->items as $item) {
$item->appendIngestPath($version);
}
}

public function __toString()
{
$data = implode(
Expand Down
7 changes: 5 additions & 2 deletions agent/src/EnvelopeForwarder.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,12 @@ public function forward(Envelope $envelope): PromiseInterface
return resolve(null);
}

$client = self::IDENTIFIER . '/' . self::VERSION;
$envelope->appendIngestPath($client);

$authHeader = [
'sentry_version=' . self::PROTOCOL_VERSION,
'sentry_client=' . self::IDENTIFIER . '/' . self::VERSION,
'sentry_client=' . $client,
'sentry_key=' . $dsn->getPublicKey(),
];

Expand All @@ -95,7 +98,7 @@ public function forward(Envelope $envelope): PromiseInterface
return (new Browser())->withTimeout($this->timeout)->post(
$dsn->getEnvelopeApiEndpointUrl(),
[
'User-Agent' => self::IDENTIFIER . '/' . self::VERSION,
'User-Agent' => $client,
'Content-Type' => Envelope::CONTENT_TYPE,
'X-Sentry-Auth' => 'Sentry ' . implode(', ', $authHeader),
],
Expand Down
41 changes: 41 additions & 0 deletions agent/src/EnvelopeItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@

namespace Sentry\Agent;

use Sentry\Util\JSON;

/**
* @internal
*
* @phpstan-type EnvelopeItemHeader array{
* type: string,
* length?: int,
* }
*/
class EnvelopeItem
{
private const EVENT_ITEM_TYPES_WITH_INGEST_PATH = [
'event' => true,
'transaction' => true,
];

/**
* @var EnvelopeItemHeader The envelope item header
*/
Expand Down Expand Up @@ -46,6 +54,39 @@ public function getData(): string
return $this->data;
}

public function appendIngestPath(string $version): void
{
if (!isset(self::EVENT_ITEM_TYPES_WITH_INGEST_PATH[$this->header['type']])) {
return;
}

$payload = json_decode($this->data, true);

if (!\is_array($payload)) {
return;
}

if (!isset($payload['ingest_path']) || !\is_array($payload['ingest_path'])) {
$payload['ingest_path'] = [];
}

$payload['ingest_path'][] = [
'version' => $version,
];

try {
$data = JSON::encode($payload);
} catch (\Throwable $e) {
return;
}

$this->data = $data;

if (isset($this->header['length'])) {
$this->header['length'] = \strlen($this->data);
}
}

public function __toString()
{
return json_encode($this->header) . "\n" . $this->data;
Expand Down
5 changes: 5 additions & 0 deletions agent/tests/AgentForwardingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Sentry\Agent\Tests;

use PHPUnit\Framework\TestCase;
use Sentry\Agent\EnvelopeForwarder;
use Sentry\Event;
use Sentry\Options;
use Sentry\Serializer\PayloadSerializer;
Expand Down Expand Up @@ -32,6 +33,10 @@ public function testAgentForwardsEnvelopeToUpstream(): void
$this->assertEquals(1, $serverOutput['request_count']);
$this->assertStringContainsString('Hello from agent test!', $serverOutput['body']);
$this->assertStringContainsString('"type":"event"', $serverOutput['body']);
$this->assertStringContainsString(
'"ingest_path":[{"version":"' . str_replace('/', '\/', EnvelopeForwarder::IDENTIFIER . '/' . EnvelopeForwarder::VERSION) . '"}]',
$serverOutput['body']
);

// Verify the correct headers were sent
$this->assertArrayHasKey('X-Sentry-Auth', $serverOutput['headers']);
Expand Down
100 changes: 100 additions & 0 deletions agent/tests/EnvelopeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use PHPUnit\Framework\TestCase;
use Sentry\Agent\Envelope;
use Sentry\Agent\EnvelopeForwarder;
use Sentry\Agent\EnvelopeItem;

class EnvelopeTest extends TestCase
{
Expand Down Expand Up @@ -51,6 +53,99 @@ public function testCanParseEnvelopeWith2Items(): void
$this->assertEquals($payload, (string) $envelope);
}

public function testAppendIngestPathToEventItem(): void
{
$envelope = new Envelope(
['dsn' => 'http://public@example.com/1'],
[new EnvelopeItem(['type' => 'event'], '{"message":"test"}')]
);

$envelope->appendIngestPath($this->getIngestPathVersion());

$payload = json_decode($envelope->getItems()[0]->getData(), true);

$this->assertSame([['version' => $this->getIngestPathVersion()]], $payload['ingest_path']);
}

public function testAppendIngestPathPreservesExistingEntries(): void
{
$envelope = new Envelope(
['dsn' => 'http://public@example.com/1'],
[
new EnvelopeItem(
['type' => 'transaction'],
'{"transaction":"/test","ingest_path":[{"version":"relay/1.0.0","public_key":"abc"}]}'
),
]
);

$envelope->appendIngestPath($this->getIngestPathVersion());

$payload = json_decode($envelope->getItems()[0]->getData(), true);

$this->assertSame(
[
['version' => 'relay/1.0.0', 'public_key' => 'abc'],
['version' => $this->getIngestPathVersion()],
],
$payload['ingest_path']
);
}

public function testAppendIngestPathUpdatesLengthHeader(): void
{
$envelope = new Envelope(
['dsn' => 'http://public@example.com/1'],
[new EnvelopeItem(['type' => 'event', 'length' => 18], '{"message":"test"}')]
);

$envelope->appendIngestPath($this->getIngestPathVersion());

$item = $envelope->getItems()[0];

$this->assertSame(\strlen($item->getData()), $item->getHeader()['length']);
}

public function testAppendIngestPathReplacesInvalidExistingIngestPath(): void
{
$envelope = new Envelope(
['dsn' => 'http://public@example.com/1'],
[new EnvelopeItem(['type' => 'event'], '{"message":"test","ingest_path":"invalid"}')]
);

$envelope->appendIngestPath($this->getIngestPathVersion());

$payload = json_decode($envelope->getItems()[0]->getData(), true);

$this->assertSame([['version' => $this->getIngestPathVersion()]], $payload['ingest_path']);
}

public function testAppendIngestPathDoesNotMutateUnsupportedItems(): void
{
foreach (['log', 'check_in', 'profile', 'attachment'] as $type) {
$envelope = new Envelope(
['dsn' => 'http://public@example.com/1'],
[new EnvelopeItem(['type' => $type], '{"message":"test"}')]
);

$envelope->appendIngestPath($this->getIngestPathVersion());

$this->assertSame('{"message":"test"}', $envelope->getItems()[0]->getData());
}
}

public function testAppendIngestPathDoesNotMutateMalformedJson(): void
{
$envelope = new Envelope(
['dsn' => 'http://public@example.com/1'],
[new EnvelopeItem(['type' => 'event'], '{"message":')]
);

$envelope->appendIngestPath($this->getIngestPathVersion());

$this->assertSame('{"message":', $envelope->getItems()[0]->getData());
}

private function getFixture(string $name): string
{
$fixture = file_get_contents(__DIR__ . "/fixtures/envelopes/{$name}.dat");
Expand All @@ -62,4 +157,9 @@ private function getFixture(string $name): string
// To make it easier to edit the fixtures, we remove the trailing new line
return rtrim($fixture, "\n");
}

private function getIngestPathVersion(): string
{
return EnvelopeForwarder::IDENTIFIER . '/' . EnvelopeForwarder::VERSION;
}
}
Binary file modified bin/sentry-agent
Binary file not shown.
2 changes: 1 addition & 1 deletion bin/sentry-agent.sig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
C5A1B020D608BDEF9E7D690A7DA18DF1BE0F3FF534304B3CED4734096A415F63B448F8156224E80F530CF203582C124CE04F4BABF968F5A905DA83199B5F6EF9
D8B94BAD7E5B61D6310089C043AA6B9A3BEFD4FB4B41752004863AB4B822A2A43B49CC2587FB83446D8AA5AC8FE6A5AA6095D8DC932DE00334D1359F70C1D9A8
Loading