restangular icon indicating copy to clipboard operation
restangular copied to clipboard

selfLink doesn't behave correctly with Cross-site baseurls

Open aarcro opened this issue 11 years ago • 12 comments

I'm serving my Angular app from localhost:8000, with django running a tastypie backend on localhost:8888. I'm simulating a mobile app, so I have no need or desire to have django server the angular app.

With a config like this:

RestangularProvider.setBaseUrl('http://localhost:8888/api/v1/');  // Following the bing example
RestangularProvider.setRestangularFields({
  selfLink: 'resource_uri'
});

and resoure_uri values, which look like: "/api/v1/object/id"

The generated path when trying to put is: http://localhost:8888/api/v1//api/v1/object/id

Perhaps BaseUrl should be split to BasePath and BaseDomain?

aarcro avatar Dec 20 '13 15:12 aarcro

Also, this doesn't work:

    var site_address = "http://localhost:8888";
    console.log('Put from here:' + site_address + obj.resource_uri);
    return obj.customPUT(site_address + obj.resource_uri);

the correct address is logged, but the customPUT still goes to localhost:8000 :(

aarcro avatar Dec 20 '13 16:12 aarcro

Not the best way to submit a patch, I know, but I did this:

        /**                                                                                                                                                                                          
         * This is the BaseURL to be used with Restangular                                                                                                                                           
         */                                                                                                                                                                                          
        config.baseUrl = _.isUndefined(config.baseUrl) ? "" : config.baseUrl;                                                                                                                        
        object.setBaseUrl = function(newBaseUrl) {                                                                                                                                                   
            config.baseUrl = /\/$/.test(newBaseUrl)                                                                                                                                                  
              ? newBaseUrl.substring(0, newBaseUrl.length-1)                                                                                                                                         
              : newBaseUrl;                                                                                                                                                                          

            // grab the protocol, domain and port                                                                                                                                                    
            config.baseDomain =  absolutePattern.test(newBaseUrl)                                                                                                                                    
              ? config.baseDomain = newBaseUrl.match(/^https?:\/\/[^\/]*/i)                                                                                                                          
              : '';                                                                                                                                                                                  
            return this;                                                                                                                                                                             
        };                                                                                                                                                                                           

And this:

                if (elemSelfLink) {                                                                                                                                                                  
                  if (__this.config.isAbsoluteUrl(elemSelfLink)) {                                                                                                                                   
                    return __this.config.baseDomain + elemSelfLink;                                                                                                                                  
                  } else {                                                                                                                                                                           
                    elemUrl = elemSelfLink;                                                                                                                                                          
                  }                                                                                                                                                                                  

Hope that points you in the right direction. It seems to be working for me at the moment. Actually I can see that it would break elemSelfLink values that started with http://

aarcro avatar Dec 20 '13 16:12 aarcro

Hey,

Answering by parts:

Also, this doesn't work:

var site_address = "http://localhost:8888";
console.log('Put from here:' + site_address + obj.resource_uri);
return obj.customPUT(site_address + obj.resource_uri);

the correct address is logged, but the customPUT still goes to localhost:8000 :(

If you need to do a put to a custom URL, you should use oneUrl or allUrl. Something like Restangular.oneUrl('people', 'http://locahost:8888/people/name/123').customPUT(objectToPut). However, if it's going to locallhost, you should use "normal" Restangular behaviour.

and resoure_uri values, which look like: "/api/v1/object/id"

The generated path when trying to put is: http://localhost:8888/api/v1//api/v1/object/id

Perhaps BaseUrl should be split to BasePath and BaseDomain?

Does this happen with the latest version of Restangular? I've fixed some problems with self linking elements in version 1.2.2. If that's not working, I'll mark this as a bug and check it out.

Thanks!

mgonto avatar Dec 24 '13 20:12 mgonto

Hi @mgonto, Thanks for all your work on restangular.

I'm running into similar behavior.

Configuration:

RestangularProvider.setBaseUrl("http://localhost:3000")

RestangularProvider.setSelfLinkAbsoluteUrl("http://localhost:3000")

RestangularProvider.setRestangularFields
  selfLink: '_links.self.href' # HAL self link

When trying to retrieve posts from a user it fails to honour the baseUrl. The path is correct though, looking like the selfLink is behaving correctly.

The request goes to the nodejs server that is serving my app, instead of the api server.

Restangular.all("users").getList().then (users) ->
  user = users[0]
  user.all("posts").getList().then (posts) ->
    $scope.posts = posts

I can make it work by commenting out https://github.com/mgonto/restangular/blob/master/src/restangular.js#L27 and changing https://github.com/mgonto/restangular/blob/master/src/restangular.js#L645 to

return __this.config.absoluteUrl+elemSelfLink;

Cheers

jsmpereira avatar Feb 25 '14 14:02 jsmpereira

This issue shouldn't be closed. It still exists in 1.3.1 and based on the release notes, the behaviour hasn't changed in 1.4.0.

I'm currently circumventing this the "hard way" in a responseInterceptor:

angular.module('myapp').run([
  'Restangular',
  function(Restangular) {
    'use strict';

    // Workaround for https://github.com/mgonto/restangular/issues/493
    // Part 1: Figure out the protocol, host and port of the base url
    var parser = document.createElement('a');
    parser.href = Restangular.configuration.baseUrl;
    var baseUrl = parser.protocol + '//' + parser.host;

    Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
      if (operation === "getList") {
        // Workaround for https://github.com/mgonto/restangular/issues/493
        // Part 2: Update selfLinks to have the full URL with the host
        if (data.length && data[0].href) {
          data.forEach(function(item) {
            if (item.href && item.href[0] === '/') {
              item.href = baseUrl + item.href;
            }
          });
        }
      }

      return data;
    });
  }
]);

roxeteer avatar May 30 '14 06:05 roxeteer

I have the same problem with this where the baseURL is ignored for self links.

Additionally I am getting an issue when the links include a format suffix such as /resource/id.json then a call to a sub resources is calling /resource/id.json/subresource instead of /resource/id/subresource.json.

Can the RequestSuffix be taking into account for the self links?

scottmcdonnell avatar Jun 13 '14 17:06 scottmcdonnell

Added pull request #785 as a suggestion to fix the above issues.

scottmcdonnell avatar Jul 10 '14 13:07 scottmcdonnell

+1 for this. I've also used the dirty patch as in https://github.com/mgonto/restangular/issues/493#issuecomment-44620392 in the meantime.

RemoteCTO avatar Jul 24 '14 12:07 RemoteCTO

I use delete Restangular.configuration.absoluteUrl; as a work around

cstephe avatar Mar 12 '15 20:03 cstephe

This issue has been a long time wait (from 2013) and gaining PR in multiple issues. It would be great to increase the priority. Thanks

yusufumac avatar May 13 '16 00:05 yusufumac

If I'm understanding this correctly, this is addressed in #851?

daviesgeek avatar Jun 16 '16 21:06 daviesgeek

+1

priiduneemre avatar Oct 05 '16 14:10 priiduneemre