|
10 | 10 | (java.util Locale) |
11 | 11 | (org.apache.http HttpEntity HeaderIterator HttpHost HttpRequest |
12 | 12 | HttpEntityEnclosingRequest HttpResponse |
13 | | - HttpRequestInterceptor HttpResponseInterceptor) |
| 13 | + HttpRequestInterceptor HttpResponseInterceptor |
| 14 | + ProtocolException) |
14 | 15 | (org.apache.http.auth UsernamePasswordCredentials AuthScope |
15 | 16 | NTCredentials) |
16 | 17 | (org.apache.http.client HttpRequestRetryHandler RedirectStrategy |
|
23 | 24 | CloseableHttpResponse |
24 | 25 | HttpUriRequest HttpRequestBase) |
25 | 26 | (org.apache.http.client.protocol HttpClientContext) |
| 27 | + (org.apache.http.client.utils URIUtils) |
26 | 28 | (org.apache.http.config RegistryBuilder) |
27 | 29 | (org.apache.http.conn.routing HttpRoute HttpRoutePlanner) |
28 | 30 | (org.apache.http.conn.ssl BrowserCompatHostnameVerifier |
|
61 | 63 | (headers/assoc-join hs k v)) |
62 | 64 | (headers/header-map))))) |
63 | 65 |
|
64 | | -(def graceful-redirect-strategy |
65 | | - (reify RedirectStrategy |
66 | | - (getRedirect [this request response context] |
67 | | - (.getRedirect DefaultRedirectStrategy/INSTANCE request response context)) |
68 | | - |
69 | | - (isRedirected [this request response context] |
70 | | - (let [^HttpClientContext typed-context context |
71 | | - max-redirects (-> (.getRequestConfig typed-context) |
72 | | - .getMaxRedirects) |
73 | | - num-redirects (count (.getRedirectLocations typed-context))] |
74 | | - (if (<= max-redirects num-redirects) |
75 | | - false |
76 | | - (.isRedirected DefaultRedirectStrategy/INSTANCE |
77 | | - request response typed-context)))))) |
78 | | - |
79 | | -(defn get-redirect-strategy [redirect-strategy] |
| 66 | +(defn graceful-redirect-strategy |
| 67 | + "Similar to the default redirect strategy, however, does not throw an error |
| 68 | + when the maximum number of redirects has been reached. Still supports |
| 69 | + validating that the new redirect host is not empty." |
| 70 | + [req] |
| 71 | + (let [validate? (opt req :validate-redirects)] |
| 72 | + (reify RedirectStrategy |
| 73 | + (getRedirect [this request response context] |
| 74 | + (let [new-request (.getRedirect DefaultRedirectStrategy/INSTANCE |
| 75 | + request response context)] |
| 76 | + (when (or validate? (nil? validate?)) |
| 77 | + (let [uri (.getURI new-request) |
| 78 | + new-host (URIUtils/extractHost uri)] |
| 79 | + (when (nil? new-host) |
| 80 | + (throw |
| 81 | + (ProtocolException. |
| 82 | + (str "Redirect URI does not specify a valid host name: " |
| 83 | + uri)))))) |
| 84 | + new-request)) |
| 85 | + |
| 86 | + (isRedirected [this request response context] |
| 87 | + (let [^HttpClientContext typed-context context |
| 88 | + max-redirects (-> (.getRequestConfig typed-context) |
| 89 | + .getMaxRedirects) |
| 90 | + num-redirects (count (.getRedirectLocations typed-context))] |
| 91 | + (if (<= max-redirects num-redirects) |
| 92 | + false |
| 93 | + (.isRedirected DefaultRedirectStrategy/INSTANCE |
| 94 | + request response typed-context))))))) |
| 95 | + |
| 96 | +(defn default-redirect-strategy [^RedirectStrategy original req] |
| 97 | + "Proxies calls to whatever original redirect strategy is passed in, however, |
| 98 | + if :validate-redirects is set in the request, checks that the redirected host |
| 99 | + is not empty." |
| 100 | + (let [validate? (opt req :validate-redirects)] |
| 101 | + (reify RedirectStrategy |
| 102 | + (getRedirect [this request response context] |
| 103 | + (let [new-request (.getRedirect original request response context)] |
| 104 | + (when (or validate? (nil? validate?)) |
| 105 | + (let [uri (.getURI new-request) |
| 106 | + new-host (URIUtils/extractHost uri)] |
| 107 | + (when (nil? new-host) |
| 108 | + (throw |
| 109 | + (ProtocolException. |
| 110 | + (str "Redirect URI does not specify a valid host name: " |
| 111 | + uri)))))) |
| 112 | + new-request)) |
| 113 | + |
| 114 | + (isRedirected [this request response context] |
| 115 | + (.isRedirected original request response context))))) |
| 116 | + |
| 117 | +(defn get-redirect-strategy [{:keys [redirect-strategy] :as req}] |
80 | 118 | (case redirect-strategy |
81 | 119 | :none (reify RedirectStrategy |
82 | 120 | (getRedirect [this request response context] nil) |
83 | 121 | (isRedirected [this request response context] false)) |
84 | 122 |
|
85 | | - ;; Like default, but does not |
86 | | - :graceful graceful-redirect-strategy |
| 123 | + ;; Like default, but does not throw exceptions when max redirects is |
| 124 | + ;; reached. |
| 125 | + :graceful (graceful-redirect-strategy req) |
87 | 126 |
|
88 | | - :default (DefaultRedirectStrategy/INSTANCE) |
89 | | - :lax (LaxRedirectStrategy.) |
90 | | - nil (DefaultRedirectStrategy/INSTANCE) |
| 127 | + :default (default-redirect-strategy DefaultRedirectStrategy/INSTANCE req) |
| 128 | + :lax (default-redirect-strategy (LaxRedirectStrategy.) req) |
| 129 | + nil (default-redirect-strategy DefaultRedirectStrategy/INSTANCE req) |
91 | 130 |
|
92 | 131 | ;; use directly as reifed RedirectStrategy |
93 | 132 | redirect-strategy)) |
|
154 | 193 | (DefaultProxyRoutePlanner. (construct-http-host proxy-host proxy-port)) |
155 | 194 | (SystemDefaultRoutePlanner. (ProxySelector/getDefault))))) |
156 | 195 |
|
157 | | -(defn http-client [{:keys [redirect-strategy retry-handler uri |
158 | | - request-interceptor response-interceptor |
159 | | - proxy-host proxy-port http-builder-fns] |
| 196 | +(defn http-client [{:keys [retry-handler uri request-interceptor |
| 197 | + response-interceptor proxy-host proxy-port |
| 198 | + http-builder-fns] |
160 | 199 | :as req} |
161 | 200 | conn-mgr http-url proxy-ignore-host] |
162 | 201 | ;; have to let first, otherwise we get a reflection warning on (.build) |
163 | 202 | (let [^HttpClientBuilder builder (-> (HttpClients/custom) |
164 | 203 | (.setConnectionManager conn-mgr) |
165 | 204 | (.setRedirectStrategy |
166 | | - (get-redirect-strategy |
167 | | - redirect-strategy)) |
| 205 | + (get-redirect-strategy req)) |
168 | 206 | (add-retry-handler retry-handler) |
169 | 207 | ;; By default, get the proxy settings |
170 | 208 | ;; from the jvm or system properties |
|
188 | 226 | (http-builder-fn builder req)) |
189 | 227 | (.build builder))) |
190 | 228 |
|
191 | | -(defn http-async-client [{:keys [redirect-strategy uri |
192 | | - request-interceptor response-interceptor |
| 229 | +(defn http-async-client [{:keys [uri request-interceptor response-interceptor |
193 | 230 | proxy-host proxy-port async-http-builder-fns] |
194 | 231 | :as req} |
195 | 232 | conn-mgr http-url proxy-ignore-host] |
196 | 233 | ;; have to let first, otherwise we get a reflection warning on (.build) |
197 | 234 | (let [^HttpAsyncClientBuilder builder (-> (HttpAsyncClients/custom) |
198 | 235 | (.setConnectionManager conn-mgr) |
199 | 236 | (.setRedirectStrategy |
200 | | - (get-redirect-strategy |
201 | | - redirect-strategy)) |
| 237 | + (get-redirect-strategy req)) |
202 | 238 | ;; By default, get the proxy |
203 | 239 | ;; settings from the jvm or system |
204 | 240 | ;; properties |
|
0 commit comments