mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-07-03 06:00:52 +00:00
[PHP-Symfony] revamp the computation of the contentType (#21292)
recent commit 40894382fc9fe959f3beacd20cfd6421eaf840b0 already improved that method: before that other commit it was juste impossible to query a endpoint with a response type that was something else than application/json or application/xml. With that commit it became possible to query such endpoint provided that the client declare in its Accept header that it can cope with */* (or provided that the client omitted that header altogether). But there were still cases badly handled. For instance if an endpoint returns a response of type image/png and that it receives a query with header "Accept: image/png", then it would reply with 406. To avoid any other issue with type resolution, this commit revamps the getOutputFormat function more thoroughly and does it by implementing the specification available at https://httpwg.org/specs/rfc9110.html#field.accept ), which means that the format accepted by the client are ordered by the relative weights specified it specified.
This commit is contained in:
parent
45047b77f1
commit
6e2b4f99ba
@ -180,34 +180,56 @@ class Controller extends AbstractController
|
||||
*/
|
||||
protected function getOutputFormat(string $accept, array $produced): ?string
|
||||
{
|
||||
// Figure out what the client accepts
|
||||
$accept = preg_split("/[\s,]+/", $accept);
|
||||
// First get the list of formats accepted by the client by weight.
|
||||
// eg: text/html,*/*; q=0.7, text/*;q=0.8,text/plain;format=fixed;q=0.6 is turned to
|
||||
// [
|
||||
// text/html => 1, // because when no weight is present then the default value is 1. See https://httpwg.org/specs/rfc9110.html#quality.values .
|
||||
// */* => 0.7,
|
||||
// text/* => 0.8,
|
||||
// text/plain => 0.6,
|
||||
// ]
|
||||
// So we can subsequently order that list by descending weight (because 1 is the most prefered value, 0.001 is the least preferred)
|
||||
$weightedFormats = array();
|
||||
foreach (explode(",", str_replace(' ', '', $accept)) as $accept) {
|
||||
$exploded = explode(';', $accept);
|
||||
|
||||
// Remove q-factor weighting. E.g. "application/json;q=0.8" becomes "application/json"
|
||||
$accept = array_map(function ($type) {return explode(';', $type)[0];}, $accept);
|
||||
|
||||
if (in_array('*/*', $accept) || in_array('application/*', $accept)) {
|
||||
// Prefer JSON if the client has no preference
|
||||
if (in_array('application/json', $produced)) {
|
||||
return 'application/json';
|
||||
}
|
||||
if (in_array('application/xml', $produced)) {
|
||||
return 'application/xml';
|
||||
// If no weight is present then the default value is 1 (see https://httpwg.org/specs/rfc9110.html#quality.values )
|
||||
if (count($exploded) === 1) {
|
||||
$weight = 1.0;
|
||||
} else {
|
||||
$lastItem = end($exploded);
|
||||
if (str_starts_with($lastItem, "q=")) {
|
||||
$weight = (float) str_replace("q=", "", $lastItem);
|
||||
} else {
|
||||
$weight = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array('application/json', $accept) && in_array('application/json', $produced)) {
|
||||
return 'application/json';
|
||||
$weightedFormats[$exploded[0]] = $weight;
|
||||
}
|
||||
arsort($weightedFormats);
|
||||
|
||||
if (in_array('application/xml', $accept) && in_array('application/xml', $produced)) {
|
||||
return 'application/xml';
|
||||
// Now return the first produced format that matches
|
||||
foreach (array_keys($weightedFormats) as $acceptedFormat) {
|
||||
$acceptedFormatParts = explode('/', $acceptedFormat);
|
||||
if (count($acceptedFormatParts) != 2) {
|
||||
// badly formatted header sent by the client. Let's continue (instead of crashing)
|
||||
continue;
|
||||
}
|
||||
$acceptedFormatType = $acceptedFormatParts[0];
|
||||
$acceptedFormatSubtype = $acceptedFormatParts[1];
|
||||
|
||||
if (in_array('*/*', $accept)) {
|
||||
return $produced[0];
|
||||
foreach ($produced as $producedFormat) {
|
||||
if ($acceptedFormat === $producedFormat) {
|
||||
return $producedFormat;
|
||||
}
|
||||
if ($acceptedFormatSubtype === '*' && $acceptedFormatType === explode("/", $producedFormat)[0]) {
|
||||
return $producedFormat;
|
||||
}
|
||||
if ($acceptedFormat === "*/*") {
|
||||
return $producedFormat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach this point, we don't have a common ground between server and client
|
||||
return null;
|
||||
}
|
||||
|
@ -190,34 +190,56 @@ class Controller extends AbstractController
|
||||
*/
|
||||
protected function getOutputFormat(string $accept, array $produced): ?string
|
||||
{
|
||||
// Figure out what the client accepts
|
||||
$accept = preg_split("/[\s,]+/", $accept);
|
||||
// First get the list of formats accepted by the client by weight.
|
||||
// eg: text/html,*/*; q=0.7, text/*;q=0.8,text/plain;format=fixed;q=0.6 is turned to
|
||||
// [
|
||||
// text/html => 1, // because when no weight is present then the default value is 1. See https://httpwg.org/specs/rfc9110.html#quality.values .
|
||||
// */* => 0.7,
|
||||
// text/* => 0.8,
|
||||
// text/plain => 0.6,
|
||||
// ]
|
||||
// So we can subsequently order that list by descending weight (because 1 is the most prefered value, 0.001 is the least preferred)
|
||||
$weightedFormats = array();
|
||||
foreach (explode(",", str_replace(' ', '', $accept)) as $accept) {
|
||||
$exploded = explode(';', $accept);
|
||||
|
||||
// Remove q-factor weighting. E.g. "application/json;q=0.8" becomes "application/json"
|
||||
$accept = array_map(function ($type) {return explode(';', $type)[0];}, $accept);
|
||||
|
||||
if (in_array('*/*', $accept) || in_array('application/*', $accept)) {
|
||||
// Prefer JSON if the client has no preference
|
||||
if (in_array('application/json', $produced)) {
|
||||
return 'application/json';
|
||||
}
|
||||
if (in_array('application/xml', $produced)) {
|
||||
return 'application/xml';
|
||||
// If no weight is present then the default value is 1 (see https://httpwg.org/specs/rfc9110.html#quality.values )
|
||||
if (count($exploded) === 1) {
|
||||
$weight = 1.0;
|
||||
} else {
|
||||
$lastItem = end($exploded);
|
||||
if (str_starts_with($lastItem, "q=")) {
|
||||
$weight = (float) str_replace("q=", "", $lastItem);
|
||||
} else {
|
||||
$weight = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array('application/json', $accept) && in_array('application/json', $produced)) {
|
||||
return 'application/json';
|
||||
$weightedFormats[$exploded[0]] = $weight;
|
||||
}
|
||||
arsort($weightedFormats);
|
||||
|
||||
if (in_array('application/xml', $accept) && in_array('application/xml', $produced)) {
|
||||
return 'application/xml';
|
||||
// Now return the first produced format that matches
|
||||
foreach (array_keys($weightedFormats) as $acceptedFormat) {
|
||||
$acceptedFormatParts = explode('/', $acceptedFormat);
|
||||
if (count($acceptedFormatParts) != 2) {
|
||||
// badly formatted header sent by the client. Let's continue (instead of crashing)
|
||||
continue;
|
||||
}
|
||||
$acceptedFormatType = $acceptedFormatParts[0];
|
||||
$acceptedFormatSubtype = $acceptedFormatParts[1];
|
||||
|
||||
if (in_array('*/*', $accept)) {
|
||||
return $produced[0];
|
||||
foreach ($produced as $producedFormat) {
|
||||
if ($acceptedFormat === $producedFormat) {
|
||||
return $producedFormat;
|
||||
}
|
||||
if ($acceptedFormatSubtype === '*' && $acceptedFormatType === explode("/", $producedFormat)[0]) {
|
||||
return $producedFormat;
|
||||
}
|
||||
if ($acceptedFormat === "*/*") {
|
||||
return $producedFormat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach this point, we don't have a common ground between server and client
|
||||
return null;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user