HTTP message API (#19)

* HTTP message API

* Added MacOS CI

* Grabbed fixes for mac from aws-crt-ffi
This commit is contained in:
Justin Boswell
2021-03-25 13:14:07 -04:00
committed by GitHub
parent 974fe3d74a
commit 9c9422c21f
14 changed files with 421 additions and 69 deletions
+8
View File
@@ -203,4 +203,12 @@ final class CRT {
function input_stream_get_length($stream) {
return self::$impl->aws_crt_input_stream_get_length($stream);
}
function http_message_new_from_blob($blob) {
return self::$impl->aws_crt_http_message_new_from_blob($blob);
}
function http_message_release($message) {
self::$impl->aws_crt_http_message_release($message);
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
namespace AWS\CRT\HTTP;
use AWS\CRT\Internal\Encoding;
final class Headers {
private $headers;
public function __construct($headers = []) {
$this->headers = $headers;
}
public static function marshall($headers) {
$buf = "";
foreach ($headers->headers as $header => $value) {
$buf .= Encoding::encodeString($header);
$buf .= Encoding::encodeString($value);
}
return $buf;
}
public static function unmarshall($buf) {
$strings = Encoding::readStrings($buf);
$headers = [];
for ($idx = 0; $idx < count($strings);) {
$headers[$strings[$idx++]] = $strings[$idx++];
}
return new Headers($headers);
}
public function count() {
return count($this->headers);
}
public function get($header) {
return isset($this->headers[$header]) ? $this->headers[$header] : null;
}
public function set($header, $value) {
$this->headers[$header] = $value;
}
public function toArray() {
return array_merge($this->headers);
}
}
+73 -18
View File
@@ -2,32 +2,87 @@
namespace AWS\CRT\HTTP;
abstract class Message {
private $path = "";
private $query = [];
private $headers = [];
use AWS\CRT\NativeResource;
public function __construct($path, $query = [], $headers = []) {
use AWS\CRT\Internal\Encoding;
abstract class Message extends NativeResource {
private $method;
private $path;
private $query;
private $headers;
public function __construct($method, $path, $query = [], $headers = null) {
$this->method = $method;
$this->path = $path;
$this->query = $query;
$this->headers = $headers;
$this->headers = !is_null($headers) ? $headers : new Headers();
$this->acquire(self::$crt->http_message_new_from_blob(self::marshall($this)));
}
}
class Request extends Message {
private $body_stream = null;
public function __destruct() {
self::$crt->http_message_release($this->release());
parent::__destruct();
}
protected static function marshall($msg) {
$buf = "";
$buf .= Encoding::encodeString($msg->method);
$buf .= Encoding::encodeString($msg->pathAndQuery());
$buf .= Headers::marshall($msg->headers);
return $buf;
}
protected static function _unmarshall($buf, $class=Message::class) {
$method = Encoding::readString($buf);
$path_and_query = Encoding::readString($buf);
$parts = explode("?", $path_and_query, 2);
$path = isset($parts[0]) ? $parts[0] : "";
$query = isset($parts[1]) ? $parts[1] : "";
$headers = Headers::unmarshall($buf);
// Turn query params back into a dictionary
if (strlen($query)) {
$query = rawurldecode($query);
$query = explode("&", $query);
$query = array_reduce($query, function($params, $pair) {
list($param, $value) = explode("=", $pair, 2);
$params[$param] = $value;
return $params;
}, []);
} else {
$query = [];
}
return new $class($method, $path, $query, $headers);
}
public function pathAndQuery() {
$path = $this->path;
$queries = [];
foreach ($this->query as $param => $value) {
$queries []= urlencode($param) . "=" . urlencode($value);
}
$query = implode("&", $queries);
if (strlen($query)) {
$path = implode("?", [$path, $query]);
}
return $path;
}
public function __construct($path, $query = [], $headers = [], $body_stream = null) {
parent::__construct($path, $query, $headers);
$this->body_stream = $body_stream;
public function method() {
return $this->method;
}
}
class Response extends Message {
private $status_code;
public function path() {
return $this->path;
}
public function query() {
return $this->query;
}
public function __construct($path, $headers, $status_code) {
parent::__construct($path, [], $headers);
$this->status_code = $status_code;
public function headers() {
return $this->headers;
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace AWS\CRT\HTTP;
class Request extends Message {
private $body_stream = null;
public function __construct($method, $path, $query = [], $headers = null, $body_stream = null) {
parent::__construct($method, $path, $query, $headers);
$this->body_stream = $body_stream;
}
public static function marshall($request) {
return parent::marshall($request);
}
public static function unmarshall($buf) {
return parent::_unmarshall($buf, Request::class);
}
public function body_stream() {
return $this->body_stream;
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace AWS\CRT\HTTP;
class Response extends Message {
private $status_code;
public function __construct($method, $path, $query, $headers, $status_code) {
parent::__construct($method, $path, $query, $headers);
$this->status_code = $status_code;
}
public static function marshall($response) {
return parent::marshall($response);
}
public static function unmarshall($buf) {
return parent::_unmarshall($buf, Response::class);
}
public function status_code() {
return $this->status_code;
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace AWS\CRT\Internal;
final class Encoding {
public static function readString(&$buffer) {
list($len, $str) = self::decodeString($buffer);
// Advance by sizeof(length) + strlen(str)
$buffer = substr($buffer, 4 + $len);
return $str;
}
public static function readStrings($buffer) {
$strings = [];
while (strlen($buffer)) {
$strings []= self::readString($buffer);
}
return $strings;
}
public static function decodeString($buffer) {
$len = unpack("N", $buffer)[1];
$buffer = substr($buffer, 4);
$str = unpack("a${len}", $buffer)[1];
return [$len, $str];
}
public static function encodeString($str) {
return pack("Na*", strlen($str), $str);
}
}