Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 61 |
| RequestHandler | |
0.00% |
0 / 1 |
|
0.00% |
0 / 3 |
182 | |
0.00% |
0 / 61 |
| handle | |
0.00% |
0 / 1 |
132 | |
0.00% |
0 / 48 |
|||
| anonymous function | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| csrfToken | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\rest\RequestHandler. | |
| */ | |
| namespace Drupal\rest; | |
| use Drupal\Core\Render\RenderContext; | |
| use Drupal\Core\Routing\RouteMatchInterface; | |
| use Symfony\Component\DependencyInjection\ContainerAwareInterface; | |
| use Symfony\Component\DependencyInjection\ContainerAwareTrait; | |
| use Symfony\Component\HttpFoundation\Request; | |
| use Symfony\Component\HttpFoundation\Response; | |
| use Symfony\Component\HttpKernel\Exception\HttpException; | |
| use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException; | |
| use Symfony\Component\Serializer\Exception\UnexpectedValueException; | |
| /** | |
| * Acts as intermediate request forwarder for resource plugins. | |
| */ | |
| class RequestHandler implements ContainerAwareInterface { | |
| use ContainerAwareTrait; | |
| /** | |
| * Handles a web API request. | |
| * | |
| * @param \Drupal\Core\Routing\RouteMatchInterface $route_match | |
| * The route match. | |
| * @param \Symfony\Component\HttpFoundation\Request $request | |
| * The HTTP request object. | |
| * | |
| * @return \Symfony\Component\HttpFoundation\Response | |
| * The response object. | |
| */ | |
| public function handle(RouteMatchInterface $route_match, Request $request) { | |
| $plugin = $route_match->getRouteObject()->getDefault('_plugin'); | |
| $method = strtolower($request->getMethod()); | |
| $resource = $this->container | |
| ->get('plugin.manager.rest') | |
| ->getInstance(array('id' => $plugin)); | |
| // Deserialize incoming data if available. | |
| $serializer = $this->container->get('serializer'); | |
| $received = $request->getContent(); | |
| $unserialized = NULL; | |
| if (!empty($received)) { | |
| $format = $request->getContentType(); | |
| // Only allow serialization formats that are explicitly configured. If no | |
| // formats are configured allow all and hope that the serializer knows the | |
| // format. If the serializer cannot handle it an exception will be thrown | |
| // that bubbles up to the client. | |
| $config = $this->container->get('config.factory')->get('rest.settings')->get('resources'); | |
| $method_settings = $config[$plugin][$request->getMethod()]; | |
| if (empty($method_settings['supported_formats']) || in_array($format, $method_settings['supported_formats'])) { | |
| $definition = $resource->getPluginDefinition(); | |
| $class = $definition['serialization_class']; | |
| try { | |
| $unserialized = $serializer->deserialize($received, $class, $format, array('request_method' => $method)); | |
| } | |
| catch (UnexpectedValueException $e) { | |
| $error['error'] = $e->getMessage(); | |
| $content = $serializer->serialize($error, $format); | |
| return new Response($content, 400, array('Content-Type' => $request->getMimeType($format))); | |
| } | |
| } | |
| else { | |
| throw new UnsupportedMediaTypeHttpException(); | |
| } | |
| } | |
| // Determine the request parameters that should be passed to the resource | |
| // plugin. | |
| $route_parameters = $route_match->getParameters(); | |
| $parameters = array(); | |
| // Filter out all internal parameters starting with "_". | |
| foreach ($route_parameters as $key => $parameter) { | |
| if ($key{0} !== '_') { | |
| $parameters[] = $parameter; | |
| } | |
| } | |
| // Invoke the operation on the resource plugin. | |
| // All REST routes are restricted to exactly one format, so instead of | |
| // parsing it out of the Accept headers again, we can simply retrieve the | |
| // format requirement. If there is no format associated, just pick JSON. | |
| $format = $route_match->getRouteObject()->getRequirement('_format') ?: 'json'; | |
| try { | |
| $response = call_user_func_array(array($resource, $method), array_merge($parameters, array($unserialized, $request))); | |
| } | |
| catch (HttpException $e) { | |
| $error['error'] = $e->getMessage(); | |
| $content = $serializer->serialize($error, $format); | |
| // Add the default content type, but only if the headers from the | |
| // exception have not specified it already. | |
| $headers = $e->getHeaders() + array('Content-Type' => $request->getMimeType($format)); | |
| return new Response($content, $e->getStatusCode(), $headers); | |
| } | |
| if ($response instanceof ResourceResponse) { | |
| $data = $response->getResponseData(); | |
| // Serialization can invoke rendering (e.g., generating URLs), but the | |
| // serialization API does not provide a mechanism to collect the | |
| // bubbleable metadata associated with that (e.g., language and other | |
| // contexts), so instead, allow those to "leak" and collect them here in | |
| // a render context. | |
| // @todo Add test coverage for language negotiation contexts in | |
| // https://www.drupal.org/node/2135829. | |
| $context = new RenderContext(); | |
| $output = $this->container->get('renderer')->executeInRenderContext($context, function() use ($serializer, $data, $format) { | |
| return $serializer->serialize($data, $format); | |
| }); | |
| $response->setContent($output); | |
| if (!$context->isEmpty()) { | |
| $response->addCacheableDependency($context->pop()); | |
| } | |
| $response->headers->set('Content-Type', $request->getMimeType($format)); | |
| // Add rest settings config's cache tags. | |
| $response->addCacheableDependency($this->container->get('config.factory')->get('rest.settings')); | |
| } | |
| return $response; | |
| } | |
| /** | |
| * Generates a CSRF protecting session token. | |
| * | |
| * @return \Symfony\Component\HttpFoundation\Response | |
| * The response object. | |
| */ | |
| public function csrfToken() { | |
| return new Response(\Drupal::csrfToken()->get('rest'), 200, array('Content-Type' => 'text/plain')); | |
| } | |
| } |