Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with Middleware/CORS #212

Open
matronator opened this issue May 27, 2024 · 2 comments
Open

Issues with Middleware/CORS #212

matronator opened this issue May 27, 2024 · 2 comments

Comments

@matronator
Copy link

I've been banging my head on this for couple of hours now. I just can't seem to get CORS to work correctly. No matter what I do, no CORS headers are sent, no matter the method or URI.

Can someone please tell me what I'm missing?

config.neon (only the relevant stuff)

extensions:
    nettrine.annotations: Nettrine\Annotations\DI\AnnotationsExtension
    nettrine.cache: Nettrine\Cache\DI\CacheExtension
    middlewares: Contributte\Middlewares\DI\MiddlewaresExtension
    resource: Contributte\DI\Extension\ResourceExtension
    api: Apitte\Core\DI\ApiExtension

services:
    - App\Services\ParserService(%tplDir%)
    - App\Services\LoggerService
    # decorator.request.authentication:
    #     class: App\Api\Decorator\ExampleResponseDecorator
    #     tags: [apitte.core.decorator: [priority: 50]]
    middleware.tryCatch:
        factory: Contributte\Middlewares\TryCatchMiddleware
        tags: [middleware: [priority: 1]]
        setup:
            - setDebugMode(%debugMode%)
            - setCatchExceptions(%productionMode%) # used in debug only
            - setLogger(App\Services\LoggerService, 'info')
    middleware.logging:
        create: Contributte\Middlewares\LoggingMiddleware
        arguments: [App\Services\LoggerService]
        tags: [middleware: [priority: 100]]
    middleware.methodOverride:
        factory: Contributte\Middlewares\MethodOverrideMiddleware
        tags: [middleware: [priority: 150]]
    middleware.cors:
        factory: App\Api\Middleware\CORSMiddleware
        tags: [middleware: [priority: 200]]
    
    api.core.errorHandler: App\Model\ErrorHandler\ThrowingErrorHandler

api:
    debug: %debugMode%
    catchException: true
    plugins:
        Apitte\Core\DI\Plugin\CoreSchemaPlugin:
        Apitte\Core\DI\Plugin\CoreMappingPlugin:
            request:
                validator: Apitte\Core\Mapping\Validator\SymfonyValidator()
        Apitte\Core\DI\Plugin\CoreServicesPlugin:
        Apitte\Core\DI\Plugin\CoreDecoratorPlugin:
        Apitte\Debug\DI\DebugPlugin:
        Apitte\Middlewares\DI\MiddlewaresPlugin:
            tracy: true
            autobasepath: true
        Apitte\OpenApi\DI\OpenApiPlugin:
            swaggerUi:
                panel: %debugMode%
                url: null
                expansion: list # list|full|none
                filter: true # true|false|string
                title: Stacks Token Factory API

App/Api/Middleware/CORSMiddleware.php (I used the same as in apitte-skeleton, this version is only after trying to get it to work by trial and error)

<?php

declare(strict_types = 1);

namespace App\Api\Middleware;

use Contributte\Middlewares\IMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class CORSMiddleware implements IMiddleware
{
	private function decorate(ResponseInterface $response): ResponseInterface
	{
		return $response
			->withHeader('Access-Control-Allow-Origin', 'http://localhost:5173, http://localhost:3000, http://localhost:8000')
			->withHeader('Access-Control-Allow-Credentials', 'true')
			->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, PATCH')
			->withHeader('Access-Control-Allow-Headers', '*');
	}

	/**
	 * Add CORS headers
	 */
	public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface
	{
		if ($request->getMethod() === 'OPTIONS') {
			return $this->decorate($response);
		}

		/** @var ResponseInterface $response */
		$response = $next($request, $this->decorate($response));

		return $this->decorate($response);
	}
}

Controller.php

#[Path('/convert/{type}')]
#[Method(['POST', 'OPTIONS'])]
#[RequestBody('Entity', Entity::class, true, true)]
#[RequestParameter('type', 'string')]
public function convert(ApiRequest $request, ApiResponse $response): ApiResponse
{
    if ($request->getMethod() === 'OPTIONS') {
        return $response
            ->withHeader('Access-Control-Allow-Origin', '*')
            ->withHeader('Access-Control-Allow-Credentials', 'true')
            ->withHeader('Access-Control-Allow-Methods', '*')
            ->withHeader('Access-Control-Allow-Headers', '*')
            ->withStatus(200);
        // exit;
    }

    /** @var Template $template */
    $template = $request->getEntity();
    $type = $request->getParameter('type');

    $content = $this->parserService->getTemplate($this->parserService->getFilePath($this->parserService->getFilenameFromType($type)));
    $parsed = $this->parserService->parse($content, (array) $template->arguments);

    $response = $response->writeBody($parsed)->withHeader('Content-Type', 'text/plain');

    return $response;
}

But I still get no additional headers added to my response and Chrome still complains:

Snímek obrazovky 2024-05-27 v 2 16 31

However what I don't understand is why Chrome is complaining about no CORS headers, when the preflight check passed apparently, because the only request showing in the console is a POST request and not OPTIONS.

Request:

POST /api/template/convert/token HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: cs-CZ,cs;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 212
Content-Type: application/json
Host: localhost:8000
Origin: http://localhost:5173
Pragma: no-cache
Referer: http://localhost:5173/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
sec-ch-ua: "Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"

Response:

HTTP/1.1 500 Internal Server Error
Host: localhost:8000
Date: Mon, 27 May 2024 00:09:13 GMT
Connection: close
X-Powered-By: Nette Framework 3
X-Frame-Options: SAMEORIGIN
Set-Cookie: _nss=1; path=/; HttpOnly; SameSite=Strict
Content-Type: text/html; charset=UTF-8

But then why is the response a 500 error, that on further inspection the code shouldn't even reach that far. The actual error is a missing property on the entity (tokenSupply), which is BS, because it is sent in the payload:

{"name":"yddd","editableUri":true,"userWallet":"SP39DTEJFPPWA3295HEE5NXYGMM7GJ8MA0TQX379","tokenName":"yddd","tokenSymbol":"WDD","tokenSupply":10000,"tokenDecimals":18,"tokenURI":"","mintable":false,"burnable":false}

I am thoroughly lost...

Also, WHY ARE THERE NO HEADERS IN THE RESPONSE when I am decorating everything in the CORSMiddleware?

@f3l1x
Copy link
Member

f3l1x commented Jun 5, 2024

Hi @matronator, it's a complex bug report, thank you for that. Unfortunately I think your code is OK. I need from you to setup https://github.com/contributte/apitte-skeleton/ or pack your project (remove non-required stuff) and send it to me for further inspection. What's your choice?

@f3l1x
Copy link
Member

f3l1x commented Aug 1, 2024

ping @matronator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants