-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from rtckit/v0.3.1
v0.3.1
- Loading branch information
Showing
10 changed files
with
749 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<?php | ||
/** | ||
* RTCKit\SIP\RAckHeader Class | ||
*/ | ||
declare(strict_types = 1); | ||
|
||
namespace RTCKit\SIP\Header; | ||
|
||
use RTCKit\SIP\Response; | ||
use RTCKit\SIP\Exception\InvalidDuplicateHeader; | ||
use RTCKit\SIP\Exception\InvalidHeaderLineException; | ||
use RTCKit\SIP\Exception\InvalidHeaderValue; | ||
use RTCKit\SIP\Exception\InvalidScalarValue; | ||
|
||
/** | ||
* RAck Header Class | ||
* | ||
* https://datatracker.ietf.org/doc/html/rfc3262#section-7.2 | ||
*/ | ||
class RAckHeader | ||
{ | ||
/** @var int RSeq sequence number */ | ||
public int $rSequence; | ||
|
||
/** @var int CSeq sequence number */ | ||
public int $cSequence; | ||
|
||
/** @var string Original request method */ | ||
public string $method; | ||
|
||
final public function __construct() {} | ||
|
||
/** | ||
* RAck header value parser | ||
* | ||
* @param list<string> $hbody Header body | ||
* @throws InvalidDuplicateHeader | ||
* @throws InvalidHeaderLineException | ||
* @throws InvalidScalarValue | ||
* @return RAckHeader | ||
*/ | ||
public static function parse(array $hbody): RAckHeader | ||
{ | ||
if (isset($hbody[1])) { | ||
throw new InvalidDuplicateHeader('Cannot have more than one RAck header', Response::BAD_REQUEST); | ||
} | ||
|
||
$rack = preg_split('/\s+/', trim($hbody[0]), -1, PREG_SPLIT_NO_EMPTY); | ||
|
||
if (!is_array($rack) || (count($rack) != 3)) { | ||
throw new InvalidHeaderLineException('Invalid RAck header', Response::BAD_REQUEST); | ||
} | ||
|
||
$ret = new static; | ||
$ret->rSequence = (int) $rack[0]; | ||
|
||
if (($ret->rSequence < 0) || ($ret->rSequence > ScalarHeader::MAX_VALUE)) { | ||
throw new InvalidScalarValue('RAck provisional sequence number out of bounds', Response::BAD_REQUEST); | ||
} | ||
|
||
$ret->cSequence = (int) $rack[1]; | ||
|
||
if (($ret->cSequence < 0) || ($ret->cSequence > ScalarHeader::MAX_VALUE)) { | ||
throw new InvalidScalarValue('RAck sequence number out of bounds', Response::BAD_REQUEST); | ||
} | ||
|
||
$ret->method = $rack[2]; | ||
|
||
return $ret; | ||
} | ||
|
||
/** | ||
* RAck header value renderer | ||
* | ||
* @param string $hname Header field name | ||
* @throws InvalidHeaderValue | ||
* @return string | ||
*/ | ||
public function render(string $hname): string | ||
{ | ||
if (!isset($this->rSequence, $this->cSequence, $this->method[0])) { | ||
throw new InvalidHeaderValue('Missing Sequence(s)/Method for RAck header field value'); | ||
} | ||
|
||
return "{$hname}: {$this->rSequence} {$this->cSequence} {$this->method}\r\n"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
<?php | ||
|
||
declare(strict_types = 1); | ||
|
||
namespace RTCKit\SIP\Header; | ||
|
||
use RTCKit\SIP\Exception\InvalidDuplicateHeader; | ||
use RTCKit\SIP\Exception\InvalidHeaderLineException; | ||
use RTCKit\SIP\Exception\InvalidHeaderValue; | ||
use RTCKit\SIP\Exception\InvalidScalarValue; | ||
use RTCKit\SIP\Header\RAckHeader; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
|
||
class RAckHeaderTest extends TestCase | ||
{ | ||
public function testShouldParseWellFormedValue() | ||
{ | ||
$rack = RAckHeader::parse(['42 7 METHOD']); | ||
|
||
$this->assertNotNull($rack); | ||
$this->assertInstanceOf(RAckHeader::class, $rack); | ||
$this->assertEquals(42, $rack->rSequence); | ||
$this->assertEquals(7, $rack->cSequence); | ||
$this->assertEquals('METHOD', $rack->method); | ||
} | ||
|
||
public function testShouldNotParseMultiValue() | ||
{ | ||
$this->expectException(InvalidDuplicateHeader::class); | ||
RAckHeader::parse([ | ||
'63 7 METHOD', | ||
'41 9 INVITE', | ||
]); | ||
} | ||
|
||
public function testShouldNotParseNondelimitedComponents() | ||
{ | ||
$this->expectException(InvalidHeaderLineException::class); | ||
RAckHeader::parse(['427METHOD']); | ||
} | ||
|
||
public function testShouldNotParseNondelimitedComponents2() | ||
{ | ||
$this->expectException(InvalidHeaderLineException::class); | ||
RAckHeader::parse(['42 7METHOD']); | ||
} | ||
|
||
public function testShouldNotParseNegativeProvisionalSequence() | ||
{ | ||
$this->expectException(InvalidScalarValue::class); | ||
RAckHeader::parse(['-7 1 METHOD']); | ||
} | ||
|
||
public function testShouldNotParseNegativeSequence() | ||
{ | ||
$this->expectException(InvalidScalarValue::class); | ||
RAckHeader::parse(['7 -1 METHOD']); | ||
} | ||
|
||
public function testShouldNotParseOutOfBoundsProvisionalSequence() | ||
{ | ||
$this->expectException(InvalidScalarValue::class); | ||
RAckHeader::parse(['42949672950 1 METHOD']); | ||
} | ||
|
||
public function testShouldNotParseOutOfBoundsSequence() | ||
{ | ||
$this->expectException(InvalidScalarValue::class); | ||
RAckHeader::parse(['1 42949672950 METHOD']); | ||
} | ||
|
||
public function testShouldNotParseMissingMethod() | ||
{ | ||
$this->expectException(InvalidHeaderLineException::class); | ||
RAckHeader::parse(['7 ']); | ||
} | ||
|
||
public function testShouldNotParseMissingMethod2() | ||
{ | ||
$this->expectException(InvalidHeaderLineException::class); | ||
RAckHeader::parse(['42 1 ']); | ||
} | ||
|
||
public function testShouldRenderWellFormedValue() | ||
{ | ||
$rack = new RAckHeader; | ||
$rack->rSequence = 42; | ||
$rack->cSequence = 7; | ||
$rack->method = 'METHOD'; | ||
|
||
$rendered = $rack->render('RAck'); | ||
|
||
$this->assertNotNull($rendered); | ||
$this->assertIsString($rendered); | ||
$this->assertEquals("RAck: 42 7 METHOD\r\n", $rendered); | ||
} | ||
|
||
public function testShouldNotRenderMissingProvisionalSequence() | ||
{ | ||
$rack = new RAckHeader; | ||
$rack->method = 'METHOD'; | ||
|
||
$this->expectException(InvalidHeaderValue::class); | ||
$rack->render('RAck'); | ||
} | ||
|
||
public function testShouldNotRenderMissingProvisionalSequence2() | ||
{ | ||
$rack = new RAckHeader; | ||
$rack->cSequence = 7; | ||
$rack->method = 'METHOD'; | ||
|
||
$this->expectException(InvalidHeaderValue::class); | ||
$rack->render('RAck'); | ||
} | ||
|
||
public function testShouldNotRenderMissingSequence() | ||
{ | ||
$rack = new RAckHeader; | ||
$rack->method = 'METHOD'; | ||
|
||
$this->expectException(InvalidHeaderValue::class); | ||
$rack->render('RAck'); | ||
} | ||
|
||
public function testShouldNotRenderMissingSequence2() | ||
{ | ||
$rack = new RAckHeader; | ||
$rack->rSequence = 42; | ||
$rack->method = 'METHOD'; | ||
|
||
$this->expectException(InvalidHeaderValue::class); | ||
$rack->render('RAck'); | ||
} | ||
|
||
public function testShouldNotRenderMissingMethod() | ||
{ | ||
$rack = new RAckHeader; | ||
$rack->rSequence = 42; | ||
$rack->cSequence = 7; | ||
|
||
$this->expectException(InvalidHeaderValue::class); | ||
$rack->render('RAck'); | ||
} | ||
} |
Oops, something went wrong.