Skip to content

Commit

Permalink
Merge pull request #27 from PedroTroller/feat/415-response
Browse files Browse the repository at this point in the history
feat: return 415 response
  • Loading branch information
PedroTroller authored Nov 4, 2020
2 parents e77b567 + f2c2819 commit 1b044be
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 108 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "pedrotroller/http-markup",
"require": {
"react/promise": "^2.8",
"slim/slim": "^3.11",
"symfony/process": "^5.1"
},
Expand Down
48 changes: 47 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 22 additions & 8 deletions features/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@

declare(strict_types=1);

use Behat\Behat\Tester\Exception\PendingException;
use Behat\Behat\Context\Context;
use Behat\Gherkin\Node\PyStringNode;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ServerException;
use Psr\Http\Message\ResponseInterface;
use SebastianBergmann\Diff\Differ;
use Webmozart\Assert\Assert;

final class FeatureContext implements Context
{
/**
* @var Client
*/
private $client;
private Client $client;

/**
* @var \GuzzleHttp\Psr7\Response|null
*/
private $response;
private ?ResponseInterface $response;

public function __construct(string $host)
{
Expand All @@ -38,6 +36,7 @@ public function cleanup(): void
*/
public function iSendAMarkupFileWithContentTypeContaining(string $mimeType, PyStringNode $body): void
{
try {
$this->response = $this->client->request(
'POST',
'/',
Expand All @@ -50,6 +49,9 @@ public function iSendAMarkupFileWithContentTypeContaining(string $mimeType, PySt
'body' => (string) $body,
]
);
} catch (RequestException $requestException) {
$this->response = $requestException->getResponse();
}
}

/**
Expand Down Expand Up @@ -77,4 +79,16 @@ public function iShouldGetTheFollowingHtml(PyStringNode $html): void
throw $exception;
}
}

/**
* @Then I should get an unexpected media type http response
*/
public function iShouldGetAnUnexpectedMediaTypeHttpResponse(): void
{
if (null === $this->response) {
throw new Exception('No request sent.');
}

Assert::eq($this->response->getStatusCode(), 415);
}
}
9 changes: 9 additions & 0 deletions features/tests.feature
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,12 @@ Feature: Parse markup file and transform them
| mime type |
| text/rst |
| text/restructuredtext |

Scenario: Push an unsupported media type
When I send a markup file with content type "application/json" containing
"""
{
"foo": "bar"
}
"""
Then I should get an unexpected media type http response
211 changes: 112 additions & 99 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,112 +5,125 @@
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Symfony\Component\Process\Process;
use Slim\App;
use React\Promise\Deferred;
use React\Promise\Promise;

require_once __DIR__.'/vendor/autoload.php';

$getExtensionFromRequest = function (Request $request): string {
$type = $request->getHeader('Content-Type');

if (empty($type)) {
throw new Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException(
'No Content-Type provided'
);
}

if (is_array($type)) {
$type = current($type);
}

$formats = [
'text/asciidoc' => 'asc',
'text/creole' => 'creole',
'text/markdown' => 'md',
'text/org' => 'org',
'text/orgmode' => 'org',
'text/rdoc' => 'rdoc',
'text/restructuredtext' => 'rst',
'text/rst' => 'rst',
'text/textile' => 'textile',
'text/txstyle' => 'textile',
'text/wiki' => 'wiki',
$app = new App();

$app->post('/', function (Request $request, Response $response, array $args): Response {
$result = [
'status' => 502,
'body' => '',
];

if (false === array_key_exists($type, $formats)) {
throw new Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException(
sprintf('Unsupported Content-Type. Only %s supported', implode(', ', array_keys($formats)))
);
}

return $formats[$type];
};

$markupToHtml = function (string $markup, string $extension): string {
$temporaryFile = sprintf('%s/%s.%s', sys_get_temp_dir(), uniqid(), $extension);
$process = new Process(
[
'github-markup',
$temporaryFile,
]
);

file_put_contents($temporaryFile, $markup);
$process->run();
unlink($temporaryFile);

if ($process->isSuccessful()) {
return $process->getOutput();
}

throw new Exception($process->getErrorOutput());
};

$prettier = function (string $html): string {
$temporaryFile = sprintf('%s/%s.%s', sys_get_temp_dir(), uniqid(), 'html');
$process = new Process(
[
'prettier',
'--write',
'--ignore-unknown',
'--parser',
'html',
'--tab-width',
2,
'--print-width',
1000,
$temporaryFile,
]
);

file_put_contents($temporaryFile, $html);
$process->run();
$html = (string) file_get_contents($temporaryFile);
unlink($temporaryFile);

if ($process->isSuccessful()) {
return $html;
}

throw new Exception($process->getErrorOutput());
};

$app = new \Slim\App();

$app->post('/', function (Request $request, Response $response, array $args) use ($getExtensionFromRequest, $markupToHtml, $prettier): void {
$extension = $getExtensionFromRequest($request);
$markup = (string) $request->getBody();

try {
$html = $markupToHtml($markup, $extension);
$html = $prettier($html);
$response->getBody()->write($html);
$response->withStatus(200);
} catch (Exception $exception) {
$response->withStatus(500);
}
$deferred = new Deferred();
$promise = $deferred->promise();

$promise
->then(function (Request $request): array {
$type = $request->getHeader('Content-Type');

if (empty($type)) {
throw new Exception('No Content-Type provided', 415);
}

if (is_array($type)) {
$type = current($type);
}

$formats = [
'text/asciidoc' => 'asc',
'text/creole' => 'creole',
'text/markdown' => 'md',
'text/org' => 'org',
'text/orgmode' => 'org',
'text/rdoc' => 'rdoc',
'text/restructuredtext' => 'rst',
'text/rst' => 'rst',
'text/textile' => 'textile',
'text/txstyle' => 'textile',
'text/wiki' => 'wiki',
];

if (false === array_key_exists($type, $formats)) {
throw new Exception(
sprintf('Unsupported Content-Type. Only %s supported', implode(', ', array_keys($formats))),
415,
);
}

return [$formats[$type], (string) $request->getBody()];
})
->then(function (array $data): string {
[$extension, $markup] = $data;
$temporaryFile = sprintf('%s/%s.%s', sys_get_temp_dir(), uniqid(), $extension);
$process = new Process(
[
'github-markup',
$temporaryFile,
]
);

file_put_contents($temporaryFile, $markup);
$process->run();
unlink($temporaryFile);

if ($process->isSuccessful()) {
return $process->getOutput();
}

throw new Exception($process->getErrorOutput());
})
->then(function (string $html): string {
$temporaryFile = sprintf('%s/%s.%s', sys_get_temp_dir(), uniqid(), 'html');
$process = new Process(
[
'prettier',
'--write',
'--ignore-unknown',
'--parser',
'html',
'--tab-width',
2,
'--print-width',
1000,
$temporaryFile,
]
);

file_put_contents($temporaryFile, $html);
$process->run();
$html = (string) file_get_contents($temporaryFile);
unlink($temporaryFile);

if ($process->isSuccessful()) {
return $html;
}

throw new Exception($process->getErrorOutput());
})
->otherwise(function (Exception $exception) use (&$result) {
$result['status'] = $exception->getCode() ?: 500;
$result['body'] = $exception->getMessage();
})
->then(function (string $html) use (&$result): void {
$result['status'] = 200;
$result['body'] = $html;
})
;

$deferred->resolve($request);

$response->getBody()->write($result['body']);

return $response->withStatus($result['status']);
});

$app->get('/_ping', function (Request $request, Response $response, array $args): void {
$response->withStatus(200);
$app->get('/_ping', function (Request $request, Response $response, array $args): Response {
return $response->withStatus(200);
});

$app->run();

0 comments on commit 1b044be

Please sign in to comment.