private function initIncremental()
{
$buf = "";
if ($this->boundary) {
// RFC 7578, RFC 2046 Section 5.1.1
$sep = "--{$this->boundary}";
while (\strlen($buf) < \strlen($sep) + 4) {
if (!(yield $this->body->valid())) {
return $this->fail(new ClientException());
}
$buf .= $this->body->consume();
}
$off = \strlen($sep);
if (strncmp($buf, $sep, $off)) {
return $this->fail(new ClientException());
}
$sep = "\r\n{$sep}";
while (substr_compare($buf, "--\r\n", $off)) {
$off += 2;
while (($end = strpos($buf, "\r\n\r\n", $off)) === false) {
if (!(yield $this->body->valid())) {
return $this->fail(new ClientException());
}
$off = \strlen($buf);
$buf .= $this->body->consume();
}
$headers = [];
foreach (explode("\r\n", substr($buf, $off, $end - $off)) as $header) {
$split = explode(":", $header, 2);
if (!isset($split[1])) {
return $this->fail(new ClientException());
}
$headers[strtolower($split[0])] = trim($split[1]);
}
if (!preg_match('#^\\s*form-data(?:\\s*;\\s*(?:name\\s*=\\s*"([^"]+)"|filename\\s*=\\s*"([^"]+)"))+\\s*$#', $headers["content-disposition"] ?? "", $m) || !isset($m[1])) {
return $this->fail(new ClientException());
}
$field = $m[1];
// Ignore Content-Transfer-Encoding as deprecated and hence we won't support it
if (isset($m[2])) {
$metadata = ["filename" => $m[2], "mime" => $headers["content-type"] ?? "application/octet-stream"];
} elseif (isset($headers["content-type"])) {
$metadata = ["mime" => $headers["content-type"]];
} else {
$metadata = [];
}
$dataPromisor = $this->initField($field, $metadata);
$buf = substr($buf, $end + 4);
$off = 0;
while (($end = strpos($buf, $sep, $off)) === false) {
if (!(yield $this->body->valid())) {
$e = new ClientException();
$dataPromisor->fail($e);
return $this->fail($e);
}
$buf .= $this->body->consume();
if (\strlen($buf) > \strlen($sep)) {
$off = \strlen($buf) - \strlen($sep);
$data = substr($buf, 0, $off);
if ($this->updateFieldSize($field, $data)) {
$dataPromisor->fail(new ClientSizeException());
return;
}
$dataPromisor->update($data);
$buf = substr($buf, $off);
}
}
$data = substr($buf, 0, $end);
if ($this->updateFieldSize($field, $data)) {
$dataPromisor->fail(new ClientSizeException());
return;
}
$dataPromisor->update($data);
$dataPromisor->succeed();
$off = $end + \strlen($sep);
while (\strlen($buf) < 4) {
if (!(yield $this->body->valid())) {
return $this->fail(new ClientException());
}
$buf .= $this->body->consume();
}
}
} else {
$field = null;
while ((yield $this->body->valid())) {
$new = $this->body->consume();
if ($new[0] === "&") {
if ($field !== null) {
if ($noData || $buf != "") {
$data = urldecode($buf);
if ($this->updateFieldSize($field, $data)) {
$dataPromisor->fail(new ClientSizeException());
return;
}
$dataPromisor->update($data);
$buf = "";
}
$field = null;
$dataPromisor->succeed();
} elseif ($buf != "") {
if (!($dataPromisor = $this->initField(urldecode($buf)))) {
return;
}
$dataPromisor->update("");
$dataPromisor->succeed();
$buf = "";
}
}
$buf .= strtok($new, "&");
if ($field !== null && ($new = strtok("&")) !== false) {
$data = urldecode($buf);
if ($this->updateFieldSize($field, $data)) {
$dataPromisor->fail(new ClientSizeException());
return;
}
$dataPromisor->update($data);
$dataPromisor->succeed();
$buf = $new;
$field = null;
}
while (($next = strtok("&")) !== false) {
$pair = explode("=", $buf, 2);
$key = urldecode($pair[0]);
if (!($dataPromisor = $this->initField($key))) {
return;
}
$data = urldecode($pair[1] ?? "");
if ($this->updateFieldSize($key, $data)) {
$dataPromisor->fail(new ClientSizeException());
return;
}
$dataPromisor->update($data);
$dataPromisor->succeed();
$buf = $next;
}
if ($field === null) {
if (($new = strstr($buf, "=", true)) !== false) {
$field = urldecode($new);
if (!($dataPromisor = $this->initField($field))) {
return;
}
$buf = substr($buf, \strlen($new) + 1);
$noData = true;
} elseif (\strlen($buf) > $this->maxFieldLen) {
return $this->fail();
}
}
if ($field !== null && $buf != "" && (\strlen($buf > 2) || $buf[0] !== "%")) {
if (\strlen($buf) > 1 ? false !== ($percent = strrpos($buf, "%", -2)) : !($percent = $buf[0] !== "%")) {
if ($percent) {
if ($this->updateFieldSize($field, $data)) {
return;
}
$dataPromisor->update(urldecode(substr($buf, 0, $percent)));
$buf = substr($buf, $percent);
}
} else {
$data = urldecode($buf);
if ($this->updateFieldSize($field, $data)) {
$dataPromisor->fail(new ClientSizeException());
return;
}
$dataPromisor->update($data);
$buf = "";
}
$noData = false;
}
}
if ($field !== null) {
if ($noData || $buf) {
$data = urldecode($buf);
if ($this->updateFieldSize($field, $data)) {
return;
}
$dataPromisor->update($data);
}
$dataPromisor->succeed();
$field = null;
} elseif ($buf) {
$field = urldecode($buf);
if (!($dataPromisor = $this->initField($field))) {
return;
}
$dataPromisor->update("");
$dataPromisor->succeed();
}
}
foreach ($this->bodyPromisors as $fieldArray) {
foreach ($fieldArray as list($promisor, $metadata)) {
$promisor->succeed();
$metadata->succeed([]);
}
}
}