|
252 | 252 | (response (exceptions-response req resp))) |
253 | 253 | raise)))) |
254 | 254 |
|
255 | | -(declare wrap-redirects) |
256 | 255 | (declare reuse-pool) |
257 | 256 |
|
258 | | -(defn- follow-redirect-request |
259 | | - [req redirect trace-redirects resp] |
260 | | - (-> req |
261 | | - (merge (parse-url redirect)) |
262 | | - (dissoc :query-params) |
263 | | - (assoc :url redirect) |
264 | | - (assoc :trace-redirects trace-redirects) |
265 | | - (reuse-pool resp))) |
266 | | - |
267 | | -(defn follow-redirect |
268 | | - "Attempts to follow the redirects from the \"location\" header, if no such |
269 | | - header exists (bad server!), returns the response without following the |
270 | | - request." |
271 | | - [client {:keys [uri url scheme server-name server-port async? respond raise] |
272 | | - :as req} |
273 | | - {:keys [trace-redirects ^InputStream body] :as resp}] |
274 | | - (let [url (or url (str (name scheme) "://" server-name |
275 | | - (when server-port (str ":" server-port)) uri))] |
276 | | - (if-let [raw-redirect (get-in resp [:headers "location"])] |
277 | | - (let [redirect (str (URL. (URL. url) raw-redirect))] |
278 | | - (try (.close body) (catch Exception _)) |
279 | | - (if-not async? |
280 | | - ((wrap-redirects client) |
281 | | - (follow-redirect-request req redirect trace-redirects resp)) |
282 | | - (if (some nil? [respond raise]) |
283 | | - (raise |
284 | | - (IllegalArgumentException. |
285 | | - "If :async? is true, you must set :respond and :raise")) |
286 | | - ((wrap-redirects client) |
287 | | - (follow-redirect-request req redirect trace-redirects resp) |
288 | | - respond raise)))) |
289 | | - ;; Oh well, we tried, but if no location is set, return the response |
290 | | - (if-not async? |
291 | | - resp |
292 | | - (respond resp))))) |
293 | | - |
294 | 257 | (defn- respond* |
295 | 258 | [resp req] |
296 | 259 | (if (:async? req) |
297 | 260 | ((:respond req) resp) |
298 | 261 | resp)) |
299 | 262 |
|
300 | | -(defn- redirects-response |
301 | | - [client |
302 | | - {:keys [request-method max-redirects redirects-count trace-redirects url] |
303 | | - :or {redirects-count 1 trace-redirects [] |
304 | | - ;; max-redirects default taken from Firefox |
305 | | - max-redirects 20} |
306 | | - :as req} {:keys [status] :as resp}] |
307 | | - (let [resp-r (assoc resp :trace-redirects |
308 | | - (if url |
309 | | - (conj trace-redirects url) |
310 | | - trace-redirects))] |
311 | | - (cond |
312 | | - (false? (opt req :follow-redirects)) |
313 | | - (respond* resp req) |
314 | | - (not (redirect? resp-r)) |
315 | | - (respond* resp-r req) |
316 | | - (and max-redirects (> redirects-count max-redirects)) |
317 | | - (if (opt req :throw-exceptions) |
318 | | - (throw (ex-info (format "Too many redirects: %s" redirects-count) resp-r)) |
319 | | - (respond* resp-r req)) |
320 | | - (= 303 status) |
321 | | - (follow-redirect client (assoc req :request-method :get |
322 | | - :redirects-count (inc redirects-count)) |
323 | | - resp-r) |
324 | | - (#{301 302} status) |
325 | | - (cond |
326 | | - (#{:get :head} request-method) |
327 | | - (follow-redirect client (assoc req :redirects-count |
328 | | - (inc redirects-count)) resp-r) |
329 | | - (opt req :force-redirects) |
330 | | - (follow-redirect client (assoc req |
331 | | - :request-method :get |
332 | | - :redirects-count (inc redirects-count)) |
333 | | - resp-r) |
334 | | - :else |
335 | | - (respond* resp-r req)) |
336 | | - (= 307 status) |
337 | | - (if (or (#{:get :head} request-method) |
338 | | - (opt req :force-redirects)) |
339 | | - (follow-redirect client (assoc req :redirects-count |
340 | | - (inc redirects-count)) resp-r) |
341 | | - (respond* resp-r req)) |
342 | | - :else |
343 | | - (respond* resp-r req)))) |
344 | | - |
345 | | -(defn ^:deprecated wrap-redirects |
346 | | - "Middleware that follows redirects in the response. A ex-info exception is |
347 | | - thrown if too many redirects occur. Options |
348 | | -
|
349 | | - :follow-redirects - default:true, whether to follow redirects |
350 | | - :max-redirects - default:20, maximum number of redirects to follow |
351 | | - :force-redirects - default:false, force redirecting methods to GET requests |
352 | | -
|
353 | | - In the response: |
354 | | -
|
355 | | - :redirects-count - number of redirects |
356 | | - :trace-redirects - vector of sites the request was redirected from" |
357 | | - [client] |
358 | | - (fn |
359 | | - ([req] |
360 | | - (redirects-response client req (client req))) |
361 | | - ([req respond raise] |
362 | | - (client req |
363 | | - #(redirects-response client |
364 | | - (assoc req :async? true |
365 | | - :respond respond |
366 | | - :raise raise) |
367 | | - %) |
368 | | - raise)))) |
369 | | - |
370 | 263 | ;; Multimethods for Content-Encoding dispatch automatically |
371 | 264 | ;; decompressing response bodies |
372 | 265 | (defmulti decompress-body |
|
0 commit comments