Symfony Route with Slash (/) in parameter not working - symfony

I have a Symfony Route configured with annotations where I want the last parameter to allow for slashes in it.
#[Route('/getFtp/{customerName}/{taskId}/{domainName}', name: 'get_ftp', requirements: ['domainName' => '.+'])]
public function index(string $customerName, string $taskId, string $domainName): Response
According to documentation https://symfony.com/doc/6.0/routing.html#slash-characters-in-route-parameters this should work.
It works for
http://mgr2.example.com/getFtp/quadramedia/abcdef/http:
but not for
http://mgr2.example.com/getFtp/quadramedia/abcdef/http:%2F

Using your exemple in my own project worked.
I tryied this url http://127.0.0.1:8080/getFtp/thomas/23/http:%2F
And then i dumped my param to be sure and got :
So, it is on your project that something is wrong.
I expect something like an other route is matching.
Try to define the route in yaml (or just on top of your controller) and put it on top of all the other to be completely sure that this is not working.
By the way, i tried your case in php 8.1 and Symfony 6.2

It works in Symfony 5.x versions. I would suggest take domainName as a request parameter in an argument. For example:
#[Route('/getFtp/{customerName}/{taskId}', name: 'get_ftp')]
public function index(string $customerName, string $taskId, Request $request): Response
{
$domainName = $request->query->get('domainName');
...
}

Related

How to programatically change the routing to add my own "filter" by keyword

My case is the following:
I have a Shopware Bundle and i need to change/extend the routing in such a way that if a request URL contains a keyword "xyz", the request is forwarded to a controller in my bundle without checking further if the route is available in "static routes" for example.
For instance: "/xyz/1/lorem/3" or "/xyz/5/3/ipsum" etc. all need to be rerouted to the controller in my bundle, since they contain the keyword /xyz.
Is there a service i can overwrite/decorate or something similar where i can implement this behaviour?
You can have a placeholder in your route with a default and a requirement allowing for all characters:
/**
* #Route("/xyz{anything}", name="frontend.my.action", methods={"GET"}, defaults={"anything"=""}, requirements={"anything"=".+"})
*/
public function myAction(Request $request): Response
{
$anything = $request->get('anything');
// ...
}
This will match any url starting with /xyz and every set of characters that follows afterwards is considered to be part of anything.

Shopware 6 backend controller path

In Shopware 6, I want to call a backend (/admin) API controller from a backend / admin page using JavaScript. What is the correct way to use a relative path, probably with a built-in getter function?
Fetching /api/v1 only works if the shop is on /, but not when it is in a sub-folder.
fetch('/api/v1/my-plugin/my-custom-action', ...)
The best practice would be to write your own JS service that handles communication with your api endpoint.
We have an abstract ApiService class, you can inherit from. You can take a look at the CalculatePriceApiService for an example in the platform.
For you an implementation might look like this:
class MyPluginApiService extends ApiService {
constructor(httpClient, loginService, apiEndpoint = 'my-plugin') {
super(httpClient, loginService, apiEndpoint);
this.name = 'myPluginService';
}
myCustomAction() {
return this.httpClient
.get('my-custom-action', {
headers: this.getBasicHeaders()
})
.then((response) => {
return ApiService.handleResponse(response);
});
}
}
Notice that your api service is preconfigured to talk to your my-plugin endpoint, in the first line of the constructor, which means in all the following request you make you can use the relative route path.
Keep also in mind that the abstract ApiService will take care of resolving the configuratuion used for the Requests. Especially this means the ApiService will use the right BaseDomain including subfolders and it will automatically use an apiVersion that is supported by your shopware version. This means the apiVersion the ApiService uses in the route will increase every time a new api version is available, that means you need to work with wildcards in your backend route annotations for the api version.
Lastly keep in mind you need to register that service. That is documented here.
For you this might look like this:
Shopware.Application.addServiceProvider('myPluginService', container => {
const initContainer = Shopware.Application.getContainer('init');
return new MyPluginApiService(initContainer.httpClient, Shopware.Service('loginService'));
});
If you are talking about custom action that you implemented, you need to define route (use annotation) and register controller in routes.xml in your Resources\config\routes.xml.
Please follow that documentation
https://docs.shopware.com/en/shopware-platform-dev-en/how-to/api-controller

.Net core Routing URLEncoded URL not working

I have a .Net core 2.2 WebAPI that works perfectly fine with "normal" style URLs e.g. /api/controller/action/param etc. I have a 3rd party service that does a POST to this API with a URL encoded path and the Asp.Net routing fails to route this request correctly.
The controller is at: .../api/file/uploadFile/{filename}
The POST from the 3rd party is:
".../api%2Ffile%2FuploadFile%2FMaintenanceReport_2019_08_05_17_11_10.html.gz".
Replacing the %2F in the path appears to work as expected:
".../api/file/uploadFile/MaintenanceReport_2019_08_05_17_11_10.html.gz"
The filename is: "MaintenanceReport_2019_08_05_17_11_10.html.gz"
Placing a Route Attribute with %2F instead of "/" sort of works, but looks very messy.
The filename passed into the path is also not resolving correctly as a parameters. I suspect this is due to the file extension being included.
I've searched the net and did not find anything related jumping out at me. Any suggestions/ideas?
[Route("api/[controller]/[action]")]
[Route("api%2F[controller]%2F[action]")]
public class FileController : Controller
{
...
}
I would have thought that the .Net core routing engine would detect the path
The default path separator in the url generated by the route is / .The issue seems that the separator before the parameter which is as part of the path value is not recognized or missing .
If you request the url like .../api%2Ffile%2FuploadFile%2FMaintenanceReport_2019_08_05_17_11_10.html.gz , you could try to use URL Rewriting Middleware like below :
In Configure
app.UseRewriter(new RewriteOptions()
.Add(RewriteRouteRules.ReWriteRequests)
);
2.Custom a class containing ReWriteRequests
public class RewriteRouteRules
{
public static void ReWriteRequests(RewriteContext context)
{
var request = context.HttpContext.Request;
if (request.Path.Value.Contains("%2F", StringComparison.OrdinalIgnoreCase))
{
context.HttpContext.Request.Path = context.HttpContext.Request.Path.Value.Replace("%2F", "/");
}
}
}
Reference: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-2.1&tabs=aspnetcore2x

Symfony: How encode / in URL parameter?

I want to build RESTful API with URLs something like:
First route: http://example.com/api/{element_name}/aaa/{related_name} and
Second route: http://example.com/api/{element_name}/bbb/{related_name}.
Everything is simple and easy when element_name is integer or simple text.
Things get complicated when parameter {element_name} has "/" char in the name, because even if I encode / by %2f (url encode) routing will decode %2f before process routes.
For example when I want to generate URL to first route and I have {element_name} = xyz and {related_name} = ooo then the URL will be http://example.com/api/xyz/aaa/ooo and it's OK.
But when I have {element_name} = xyz/bbb and {related_name} = ooo then the URL should be: http://example.com/api/xyz%2fbbb/aaa/ooo but routing first will decode url and make: http://example.com/api/xyz/bbb/aaa/ooo and it isn't OK because doesn't match to first route.
How I should do that?
All you need to do is to add requirement while configuring the routes in your controller. Like so :
class DefaultController
{
/**
* #Route("/share/{token}", name="share", requirements={"token"=".+"})
*/
public function share($token)
{
// ...
}
}
it's explained in the SF doc: http://symfony.com/doc/current/routing/slash_in_parameter.html

Matching a URL to a route in Symfony

We have files behind authentication, and I want to do different things for post-authentication redirect if the user entered the application using a URL of a file versus a URL of an HTML resource.
I have a URL: https://subdomain.domain.com/resource/45/identifiers/567/here/11abdf51e3d7-some%20file%20name.png/download. I want to get the route name for this URL.
app/console router:debug outputs this: _route_name GET ANY subdomain.domain.{tld} /resource/{id2}/identifiers/{id2}/here/{id3}/download.
Symfony has a Routing component (http://symfony.com/doc/current/book/routing.html), and I'm trying to call match() on an instance of Symfony\Bundle\FrameworkBundle\Routing\Router as provided by Symfony IOC. I have tried with with the domain and without the domain, but they both create a MethodNotAllowed exception because the route cannot be found. How can I match this URL to a route?
Maybe a bit late but as I was facing the same problem, what I come to is something like
$request = Request::create($targetPath, Request::METHOD_GET, [], [], [], $_SERVER);
try {
$matches = $router->matchRequest($request);
} catch (\Exception $e) {
// throw a 400
}
The key part is to use $_SERVER superglobal array in order to have all things setted straight away.
According to this, Symfony uses current request's HTTP method while matching. I guess your controller serves POST request, while your download links are GET.
The route name is available in the _route_name attribute of the Request object: $request->attributes->get('_route_name').
You can do something like this ton get the route name:
public/protected/private function getRefererRoute(Request $request = null)
{
if ($request == null)
$request = $this->getRequest();
//look for the referer route
$referer = $request->headers->get('referer');
$path = substr($referer, strpos($referer, $request->getBaseUrl()));
$path = str_replace($request->getBaseUrl(), '', $lastPath);
$matcher = $this->get('router')->getMatcher();
$parameters = $matcher->match($path);
$route = $parameters['_route'];
return $route;
}
EDIT:
I forgot to explain what I was doing. So basicly you are getting the page url ($referer) then taking out your website's base url with str_replace and then trying to match the remaining part of the path with a know route pattern using route matcher.
EDIT2:
Obviously you need to have this inside you controller if you want to be able to use $this->get(...)

Resources