Skip to content
This repository has been archived by the owner on Dec 9, 2024. It is now read-only.

Support OPTIONS method #66

Open
wants to merge 3 commits into
base: 8.x-1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions config/install/relaxed.settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ resources:
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
POST:
supported_formats:
- json
Expand Down Expand Up @@ -45,6 +51,12 @@ resources:
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
PUT:
supported_formats:
- json
Expand All @@ -64,13 +76,25 @@ resources:
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
relaxed:changes:
GET:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
relaxed:doc:
HEAD:
supported_formats:
Expand All @@ -85,6 +109,12 @@ resources:
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
PUT:
supported_formats:
- json
Expand All @@ -105,6 +135,12 @@ resources:
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
relaxed:local:doc:
HEAD:
supported_formats:
Expand All @@ -118,6 +154,12 @@ resources:
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
PUT:
supported_formats:
- json
Expand All @@ -131,31 +173,61 @@ resources:
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
relaxed:session:
GET:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
relaxed:ensure_full_commit:
POST:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
relaxed:all_dbs:
GET:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
relaxed:all_docs:
GET:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
OPTIONS:
supported_formats:
- json
supported_auth:
- cookie
- basic_auth
7 changes: 6 additions & 1 deletion relaxed.services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,9 @@ services:
class: Drupal\relaxed\CouchdbReplicator
arguments: ['@config.factory']
tags:
- {name: workspace_replicator, priority: 10}
- {name: workspace_replicator, priority: 10}
relaxed.options_request_listener:
class: Drupal\relaxed\EventSubscriber\OptionsRequestSubscriber
arguments: ['@router.route_provider']
tags:
- { name: event_subscriber }
77 changes: 77 additions & 0 deletions src/EventSubscriber/OptionsRequestSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

/**
* @file
* Contains \Drupal\relaxed\EventSubscriber\OptionsRequestSubscriber.
*/

namespace Drupal\relaxed\EventSubscriber;

use Drupal\Core\Url;
use Symfony\Cmf\Component\Routing\RouteProviderInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
* Handles options requests.
*
* Therefore it sends a options response using all methods on all possible
* routes.
* @todo Review/remove this when https://www.drupal.org/node/2237231 lands.
*/
class OptionsRequestSubscriber implements EventSubscriberInterface {

/**
* @var \Symfony\Cmf\Component\Routing\RouteProviderInterface
*/
protected $routeProvider;

/**
* Creates a new OptionsRequestSubscriber instance.
*
* @param \Symfony\Cmf\Component\Routing\RouteProviderInterface $routeProvider
* THe route provider.
*/
public function __construct(RouteProviderInterface $routeProvider) {
$this->routeProvider = $routeProvider;
}

/**
* Tries to handle the options request.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The request event.
*/
public function onRequest(GetResponseEvent $event) {
if ($event->getRequest()->isMethod('OPTIONS')) {
$routes = $this->routeProvider->getRouteCollectionForRequest($event->getRequest());
// In case we don't have any routes, a 403 should be thrown by the normal
// request handling.
$methods = [];
if (count($routes) > 0) {
$current_route_name = Url::createFromRequest($event->getRequest())->getRouteName();
$current_route = $this->routeProvider->getRouteByName($current_route_name);
foreach ($routes as $route) {
if ($current_route->getPath() !== $route->getPath()) {
continue;
}
$methods = array_merge($methods, $route->getMethods());
}
$response = new Response('', 200, ['Allow' => implode(', ', $methods)]);
$event->setResponse($response);
}
}
}

/**
* {@inheritdoc}
*/
public static function getSubscribedEvents() {
// Set a high priority so its executed before routing.
$events[KernelEvents::REQUEST][] = ['onRequest', 1000] ;
return $events;
}

}
9 changes: 8 additions & 1 deletion src/Plugin/rest/resource/ChangesResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace Drupal\relaxed\Plugin\rest\resource;

use Drupal\multiversion\Entity\WorkspaceInterface;
use Drupal\relaxed\Changes\Changes;
use Drupal\rest\ResourceResponse;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -27,8 +28,14 @@
*/
class ChangesResource extends ResourceBase {

/**
* @param $workspace
*
* @return ResourceResponse
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function get($workspace) {
if (is_string($workspace)) {
if (!$workspace instanceof WorkspaceInterface) {
throw new NotFoundHttpException();
}

Expand Down
42 changes: 41 additions & 1 deletion src/Plugin/rest/resource/ResourceBase.php
Original file line number Diff line number Diff line change
@@ -1,15 +1,54 @@
<?php

/**
* @file
* Contains \Drupal\relaxed\Plugin\rest\resource\ResourceBase.
*/

namespace Drupal\relaxed\Plugin\rest\resource;

use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\multiversion\Entity\WorkspaceInterface;
use Drupal\rest\Plugin\ResourceBase as CoreResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

abstract class ResourceBase extends CoreResourceBase implements RelaxedResourceInterface {

/**
* @param $workspace
*
* @return ResourceResponse
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function options($workspace) {
if (!$workspace instanceof WorkspaceInterface) {
throw new NotFoundHttpException();
}
$response = new ResourceResponse(NULL, 204);
$response->addCacheableDependency($workspace);

return $response;
}

/**
* {@inheritdoc}
*/
public function availableMethods() {
$methods = parent::availableMethods();

// Indiscriminately patch in OPTIONS as an accepted method, to facilitate
// CORS for all RELAXed endpoints.
if (!in_array('OPTIONS', $methods)) {
$methods[] = 'OPTIONS';
}

return $methods;
}

/**
* {@inheritdoc}
*/
Expand All @@ -29,7 +68,7 @@ public function routes() {

// Allow pull or push permissions depending on the method.
$permissions = 'perform push replication';
if ($method === 'GET') {
if (in_array($method, ['GET', 'OPTIONS'])) {
$permissions .= '+perform pull replication';
}

Expand Down Expand Up @@ -81,6 +120,7 @@ public function routes() {
break;

case 'GET':
case 'OPTIONS':
$collection->add("$route_name.$method", $route);
break;

Expand Down