user796443
user796443

Reputation:

laravel asset() method doesn't return https

I'm using asset() public method to generate correct url in laravel.

in docs it says:

enter image description here

So in theory it should detect correct scheme itself.

But in code I see: https://github.com/illuminate/routing/blob/master/UrlGenerator.php#L210

public function asset($path, $secure = null)
    {

default for secure is null. So this method is no good for both http/https.

what am I missing here?

I'm using reverse proxy, could it because of that?

Upvotes: 9

Views: 9827

Answers (7)

Akshay K Nair
Akshay K Nair

Reputation: 1476

Please stop writing code for doing things that already exist. There is a ASSET_URL env variable. Use it.

ASSET_URL=https://your.app.url #in env for production

ASSET_URL=http://your.app.url #in env for local development

( https://stackoverflow.com/a/68287406/7481663 )

Upvotes: 7

I was doing some maintenance in some legacy systems built in Laravel 4.2 and stumbled in this situation.

After giving a look at how the Generators are instantiated and used, I solved the problem setting the UrlGenerator forcedSchema property after the environment detection at the start.php file of the application.

// The if condition depends on what identifies your https host
if( str_contains($_SERVER['HTTP_HOST'], 'secure_app_host_fragment')){
    $app['url']->forceSchema('https');
}

Code: https://github.com/laravel/framework/blob/7d9e7068c49f945385673014d4cba4de28accd5e/src/Illuminate/Routing/UrlGenerator.php#L204

Upvotes: 0

Kat Lim Ruiz
Kat Lim Ruiz

Reputation: 2562

Yes, that happens because the reverse proxy will do SSL termination, which means that the browser requests https, but the request that goes from the proxy to the app is http. This has many benefits (improved performance) but it does have this side-effect.

I think the solution would go as an environment variable that tells you to force https (when using the web on staging or production) or to leave as http when e.g. developing locally.

I think is the most effective. I say this because your app will never know when to use https or not.

Upvotes: 2

valmayaki
valmayaki

Reputation: 301

In case anyone falls into this same issue like I did in order to allow the asset function to get the proper schema you would have to enable TrustedProxies. In laravel there is a middleware that does that for you in \App\Http\Middleware\TrustedProxies but you must included it in your default middleware before it can take effect.

Laravel uses the fideloper/TrustedProxy package which sets the trustedProxies array in the Request object which is checked in order to approve the X-Forwarded-Proto provided in the header.

You can check the following link to get more details

Explains in Laravel Trusted Proxy in details

For Setting it up

Upvotes: 1

Francesco Casula
Francesco Casula

Reputation: 27190

As you can see from GitHub the asset method is calling getScheme to determine what the scheme should be.

https://github.com/illuminate/routing/blob/master/UrlGenerator.php#L303

public function formatScheme($secure = null)
{
    if (! is_null($secure)) {
        return $secure ? 'https://' : 'http://';
    }
    if (is_null($this->cachedScheme)) {
        $this->cachedScheme = $this->forceScheme ?: $this->request->getScheme().'://';
    }
    return $this->cachedScheme;
}

So if you don't provide the asset 2nd parameter $secure then it uses the request scheme. Otherwise you can provide $secure to force the desired scheme regardless of what is the scheme in the request.

If you look at the code you'll see that if $secure is null and no cache is set than the cache is set to the request scheme (i.e. $this->request->getScheme()) and therefore returned.

Upvotes: 3

Orange Lux
Orange Lux

Reputation: 2037

On the very same file, you have a definition of the getScheme() method, which uses the $secure parameter.

If the $secure parameter is the default null value, the scheme is either guessed from the current scheme, or retrieved from the previous saved scheme (If it hasn't been forced with forceSchema()).

You could tell the $secure parameter works that way :

  • true will force https
  • false will force http
  • null will use the best scheme, guessed from the current scheme

Here's the code from the getScheme() method :

protected function getScheme($secure)
{
    if (is_null($secure)) {
        if (is_null($this->cachedSchema)) {
            $this->cachedSchema = $this->forceSchema ?: $this->request->getScheme().'://';
        }
        return $this->cachedSchema;
    }
    return $secure ? 'https://' : 'http://';
}

Upvotes: 1

swatkins
swatkins

Reputation: 13640

isn't it secure_asset you're looking for?

https://laravel.com/docs/5.3/helpers#method-secure-asset

Upvotes: 3

Related Questions