lib/assets/javascripts/up/proxy.js.coffee in upjs-rails-0.17.0 vs lib/assets/javascripts/up/proxy.js.coffee in upjs-rails-0.18.0

- old
+ new

@@ -86,25 +86,38 @@ You might find it useful to set this to `1` in full-stack integration tests (e.g. Selenium). Note that your browser might [impose its own request limit](http://www.browserscope.org/?category=network) regardless of what you configure here. + @param {Array<String>} [config.wrapMethods] + An array of uppercase HTTP method names. AJAX requests with one of these methods + will be converted into a `POST` request and carry their original method as a `_method` + parameter. This is to [prevent unexpected redirect behavior](https://makandracards.com/makandra/38347). + @param {String} [config.wrapMethodParam] + The name of the POST parameter when wrapping HTTP methods in a `POST` request. + @param {Array<String>} [config.safeMethods] + An array of uppercase HTTP method names that are considered idempotent. + The proxy cache will only cache idempotent requests and will clear the entire + cache after a non-idempotent request. @stable ### config = u.config busyDelay: 300 preloadDelay: 75 cacheSize: 70 cacheExpiry: 1000 * 60 * 5 maxRequests: 4 + wrapMethods: ['PATCH', 'PUT', 'DELETE'] + wrapMethodParam: '_method' + safeMethods: ['GET', 'OPTIONS', 'HEAD'] cacheKey = (request) -> normalizeRequest(request) [ request.url, request.method, request.data, - request.selector + request.target ].join('|') cache = u.cache size: -> config.cacheSize expiry: -> config.cacheExpiry @@ -123,15 +136,15 @@ @experimental ### get = (request) -> request = normalizeRequest(request) candidates = [request] - unless request.selector is 'html' - requestForHtml = u.merge(request, selector: 'html') + unless request.target is 'html' + requestForHtml = u.merge(request, target: 'html') candidates.push(requestForHtml) - unless request.selector is 'body' - requestForBody = u.merge(request, selector: 'body') + unless request.target is 'body' + requestForBody = u.merge(request, target: 'body') candidates.push(requestForBody) for candidate in candidates if response = cache.get(candidate) return response @@ -139,11 +152,11 @@ Manually stores a promise for the response to the given request. @function up.proxy.set @param {String} request.url @param {String} [request.method='GET'] - @param {String} [request.selector='body'] + @param {String} [request.target='body'] @param {Promise} response A promise for the response that is API-compatible with the promise returned by [`jQuery.ajax`](http://api.jquery.com/jquery.ajax/). @experimental ### @@ -156,11 +169,11 @@ automatically removes cache entries. @function up.proxy.remove @param {String} request.url @param {String} [request.method='GET'] - @param {String} [request.selector='body'] + @param {String} [request.target='body'] @experimental ### remove = cache.remove ###* @@ -198,11 +211,11 @@ normalizeRequest = (request) -> unless request._normalized request.method = u.normalizeMethod(request.method) request.url = u.normalizeUrl(request.url) if request.url - request.selector ||= 'body' + request.target ||= 'body' request._normalized = true request ###* Makes a request to the given URL and caches the response. @@ -219,28 +232,30 @@ be emitted. @function up.proxy.ajax @param {String} request.url @param {String} [request.method='GET'] - @param {String} [request.selector='body'] + @param {String} [request.target='body'] @param {Boolean} [request.cache] Whether to use a cached response, if available. If set to `false` a network connection will always be attempted. @param {Object} [request.headers={}] An object of additional header key/value pairs to send along with the request. + @param {Object} [request.data={}] + An object of request parameters. @return A promise for the response that is API-compatible with the promise returned by [`jQuery.ajax`](http://api.jquery.com/jquery.ajax/). @stable ### ajax = (options) -> forceCache = (options.cache == true) ignoreCache = (options.cache == false) - request = u.only(options, 'url', 'method', 'data', 'selector', 'headers', '_normalized') + request = u.only(options, 'url', 'method', 'data', 'target', 'headers', '_normalized') pending = true # Non-GET requests always touch the network # unless `options.cache` is explicitly set to `true`. @@ -274,12 +289,10 @@ loadStarted() promise.always(loadEnded) promise - SAFE_HTTP_METHODS = ['GET', 'OPTIONS', 'HEAD'] - ###* Returns `true` if the proxy is not currently waiting for a request to finish. Returns `false` otherwise. The proxy will also emit an [`up:proxy:idle` event](/up:proxy:idle) if it @@ -370,13 +383,29 @@ request: request queuedRequests.push(entry) deferred.promise() load = (request) -> - u.debug('Loading URL %o', request.url) + u.debug('Fetching %o via %o', request.url, request.method) up.emit('up:proxy:load', request) - promise = u.ajax(request) + + # We will modify the request below for features like method wrapping. + # Let's not change the original request which would confuse API clients + # and cache key logic. + request = u.copy(request) + + request.headers ||= {} + request.headers['X-Up-Target'] = request.target + request.data = u.requestDataAsArray(request.data) + + if u.contains(config.wrapMethods, request.method) + request.data.push + name: config.wrapMethodParam + value: request.method + request.method = 'POST' + + promise = $.ajax(request) promise.always -> up.emit('up:proxy:received', request) pokeQueue() promise @@ -391,27 +420,27 @@ is starting to load. @event up:proxy:load @param event.url @param event.method - @param event.selector + @param event.target @experimental ### ###* This event is [emitted]/(up.emit) when the response to an [AJAX request](/up.proxy.ajax) has been received. @event up:proxy:received @param event.url @param event.method - @param event.selector + @param event.target @experimental ### isIdempotent = (request) -> normalizeRequest(request) - u.contains(SAFE_HTTP_METHODS, request.method) + u.contains(config.safeMethods, request.method) checkPreload = ($link) -> delay = parseInt(u.presentAttr($link, 'up-delay')) || config.preloadDelay unless $link.is($waitingLink) $waitingLink = $link