View Javadoc
1   /*
2    * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
3    * Copyright (C) 2010  Mickael Guessant
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18   */
19  
20  package davmail.http;
21  
22  import davmail.Settings;
23  import davmail.exception.*;
24  import davmail.http.request.*;
25  import org.apache.http.Header;
26  import org.apache.http.HttpResponse;
27  import org.apache.http.HttpStatus;
28  import org.apache.http.StatusLine;
29  import org.apache.http.auth.AuthSchemeProvider;
30  import org.apache.http.auth.AuthScope;
31  import org.apache.http.auth.NTCredentials;
32  import org.apache.http.client.CredentialsProvider;
33  import org.apache.http.client.HttpResponseException;
34  import org.apache.http.client.config.AuthSchemes;
35  import org.apache.http.client.config.CookieSpecs;
36  import org.apache.http.client.config.RequestConfig;
37  import org.apache.http.client.methods.CloseableHttpResponse;
38  import org.apache.http.client.methods.HttpRequestBase;
39  import org.apache.http.client.protocol.HttpClientContext;
40  import org.apache.http.client.utils.URIUtils;
41  import org.apache.http.config.Registry;
42  import org.apache.http.config.RegistryBuilder;
43  import org.apache.http.conn.HttpClientConnectionManager;
44  import org.apache.http.conn.socket.ConnectionSocketFactory;
45  import org.apache.http.conn.socket.PlainConnectionSocketFactory;
46  import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
47  import org.apache.http.cookie.Cookie;
48  import org.apache.http.impl.auth.BasicSchemeFactory;
49  import org.apache.http.impl.auth.DigestSchemeFactory;
50  import org.apache.http.impl.client.BasicCookieStore;
51  import org.apache.http.impl.client.BasicCredentialsProvider;
52  import org.apache.http.impl.client.CloseableHttpClient;
53  import org.apache.http.impl.client.HttpClientBuilder;
54  import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
55  import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
56  import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
57  import org.apache.jackrabbit.webdav.DavException;
58  import org.apache.jackrabbit.webdav.MultiStatus;
59  import org.apache.jackrabbit.webdav.MultiStatusResponse;
60  import org.apache.jackrabbit.webdav.client.methods.BaseDavRequest;
61  import org.apache.jackrabbit.webdav.client.methods.HttpCopy;
62  import org.apache.jackrabbit.webdav.client.methods.HttpMove;
63  import org.apache.log4j.Logger;
64  import org.codehaus.jettison.json.JSONObject;
65  
66  import java.io.Closeable;
67  import java.io.IOException;
68  import java.net.*;
69  import java.security.Security;
70  import java.util.HashSet;
71  import java.util.List;
72  
73  public class HttpClientAdapter implements Closeable {
74      static final Logger LOGGER = Logger.getLogger("davmail.http.HttpClientAdapter");
75  
76      static final String[] SUPPORTED_PROTOCOLS = new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
77      static final Registry<ConnectionSocketFactory> SCHEME_REGISTRY;
78      static String WORKSTATION_NAME = "UNKNOWN";
79      static final int MAX_REDIRECTS = 10;
80  
81      static {
82          // disable Client-initiated TLS renegotiation
83          System.setProperty("jdk.tls.rejectClientInitiatedRenegotiation", "true");
84          // force strong ephemeral Diffie-Hellman parameter
85          System.setProperty("jdk.tls.ephemeralDHKeySize", "2048");
86  
87          Security.setProperty("ssl.SocketFactory.provider", "davmail.http.DavGatewaySSLSocketFactory");
88  
89          // DavMail is Kerberos configuration provider
90          Security.setProperty("login.configuration.provider", "davmail.http.KerberosLoginConfiguration");
91  
92          // reenable basic proxy authentication on Java >= 1.8.111
93          System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
94  
95          RegistryBuilder<ConnectionSocketFactory> schemeRegistry = RegistryBuilder.create();
96          schemeRegistry.register("http", new PlainConnectionSocketFactory());
97          schemeRegistry.register("https", new SSLConnectionSocketFactory(new DavGatewaySSLSocketFactory(),
98                  SUPPORTED_PROTOCOLS, null,
99                  SSLConnectionSocketFactory.getDefaultHostnameVerifier()));
100 
101         SCHEME_REGISTRY = schemeRegistry.build();
102 
103         try {
104             WORKSTATION_NAME = InetAddress.getLocalHost().getHostName();
105         } catch (Exception e) {
106             // ignore
107         }
108 
109         // set system property *before* calling ProxySelector.getDefault()
110         if (Settings.getBooleanProperty("davmail.useSystemProxies", Boolean.FALSE)) {
111             System.setProperty("java.net.useSystemProxies", "true");
112         }
113         ProxySelector.setDefault(new DavGatewayProxySelector(ProxySelector.getDefault()));
114     }
115 
116     /**
117      * Test if the response is gzip encoded
118      *
119      * @param response http response
120      * @return true if response is gzip encoded
121      */
122     public static boolean isGzipEncoded(HttpResponse response) {
123         Header header = response.getFirstHeader("Content-Encoding");
124         return header != null && "gzip".equals(header.getValue());
125     }
126 
127     HttpClientConnectionManager connectionManager;
128     CloseableHttpClient httpClient;
129     CredentialsProvider provider = new BasicCredentialsProvider();
130     BasicCookieStore cookieStore = new BasicCookieStore() {
131         @Override
132         public void addCookie(final Cookie cookie) {
133             //LOGGER.debug("Add cookie " + cookie);
134             super.addCookie(cookie);
135         }
136     };
137     // current URI
138     URI uri;
139     String domain;
140     String userid;
141     String userEmail;
142 
143     public HttpClientAdapter(String url) {
144         this(URI.create(url));
145     }
146 
147     public HttpClientAdapter(String url, String username, String password) {
148         this(URI.create(url), username, password, false);
149     }
150 
151     public HttpClientAdapter(String url, boolean enablePool) {
152         this(URI.create(url), null, null, enablePool);
153     }
154 
155     public HttpClientAdapter(String url, String username, String password, boolean enablePool) {
156         this(URI.create(url), username, password, enablePool);
157     }
158 
159     public HttpClientAdapter(URI uri) {
160         this(uri, null, null, false);
161     }
162 
163     public HttpClientAdapter(URI uri, boolean enablePool) {
164         this(uri, null, null, enablePool);
165     }
166 
167     public HttpClientAdapter(URI uri, String username, String password) {
168         this(uri, username, password, false);
169     }
170 
171     public HttpClientAdapter(URI uri, String username, String password, boolean enablePool) {
172         // init current uri
173         this.uri = uri;
174 
175         if (enablePool) {
176             connectionManager = new PoolingHttpClientConnectionManager(SCHEME_REGISTRY);
177             ((PoolingHttpClientConnectionManager) connectionManager).setDefaultMaxPerRoute(5);
178             startEvictorThread();
179         } else {
180             connectionManager = new BasicHttpClientConnectionManager(SCHEME_REGISTRY);
181         }
182         HttpClientBuilder clientBuilder = HttpClientBuilder.create()
183                 .disableRedirectHandling()
184                 .setDefaultRequestConfig(getRequestConfig())
185                 .setUserAgent(getUserAgent())
186                 .setDefaultAuthSchemeRegistry(getAuthSchemeRegistry())
187                 // httpClient is not shared between clients, do not track connection state
188                 .disableConnectionState()
189                 .setConnectionManager(connectionManager);
190 
191         SystemDefaultRoutePlanner routePlanner = new SystemDefaultRoutePlanner(ProxySelector.getDefault());
192         clientBuilder.setRoutePlanner(routePlanner);
193 
194         clientBuilder.setDefaultCookieStore(cookieStore);
195 
196         setCredentials(username, password);
197 
198         boolean enableProxy = Settings.getBooleanProperty("davmail.enableProxy");
199         boolean useSystemProxies = Settings.getBooleanProperty("davmail.useSystemProxies", Boolean.FALSE);
200         String proxyHost = null;
201         int proxyPort = 0;
202         String proxyUser = null;
203         String proxyPassword = null;
204 
205         if (useSystemProxies) {
206             // get proxy for url from system settings
207             System.setProperty("java.net.useSystemProxies", "true");
208             List<Proxy> proxyList = getProxyForURI(uri);
209             if (!proxyList.isEmpty() && proxyList.get(0).address() != null) {
210                 InetSocketAddress inetSocketAddress = (InetSocketAddress) proxyList.get(0).address();
211                 proxyHost = inetSocketAddress.getHostName();
212                 proxyPort = inetSocketAddress.getPort();
213 
214                 // we may still need authentication credentials
215                 proxyUser = Settings.getProperty("davmail.proxyUser");
216                 proxyPassword = Settings.getProperty("davmail.proxyPassword");
217             }
218         } else if (isNoProxyFor(uri)) {
219             LOGGER.debug("no proxy for " + uri.getHost());
220         } else if (enableProxy) {
221             proxyHost = Settings.getProperty("davmail.proxyHost");
222             proxyPort = Settings.getIntProperty("davmail.proxyPort");
223             proxyUser = Settings.getProperty("davmail.proxyUser");
224             proxyPassword = Settings.getProperty("davmail.proxyPassword");
225         }
226 
227         if (proxyHost != null && !proxyHost.isEmpty() && (proxyUser != null && !proxyUser.isEmpty())) {
228 
229                 AuthScope authScope = new AuthScope(proxyHost, proxyPort, AuthScope.ANY_REALM);
230                 if (provider == null) {
231                     provider = new BasicCredentialsProvider();
232                 }
233 
234                 // detect ntlm authentication (windows domain name in username)
235                 int backslashIndex = proxyUser.indexOf('\\');
236                 if (backslashIndex > 0) {
237                     provider.setCredentials(authScope, new NTCredentials(proxyUser.substring(backslashIndex + 1),
238                             proxyPassword, WORKSTATION_NAME,
239                             proxyUser.substring(0, backslashIndex)));
240                 } else {
241                     provider.setCredentials(authScope, new NTCredentials(proxyUser, proxyPassword, WORKSTATION_NAME, ""));
242                 }
243 
244         }
245 
246         clientBuilder.setDefaultCredentialsProvider(provider);
247 
248         httpClient = clientBuilder.build();
249     }
250 
251     /**
252      * Get current uri host
253      *
254      * @return current host
255      */
256     public String getHost() {
257         return uri.getHost();
258     }
259 
260     /**
261      * Force current uri.
262      *
263      * @param uri new uri
264      */
265     public void setUri(URI uri) {
266         this.uri = uri;
267     }
268 
269     /**
270      * Current uri.
271      *
272      * @return current uri
273      */
274     public URI getUri() {
275         return uri;
276     }
277 
278     private Registry<AuthSchemeProvider> getAuthSchemeRegistry() {
279         final RegistryBuilder<AuthSchemeProvider> registryBuilder = RegistryBuilder.create();
280         AuthSchemeProvider ntlmSchemeProvider;
281         if (Settings.getBooleanProperty("davmail.enableJcifs", false)) {
282             ntlmSchemeProvider = new JCIFSNTLMSchemeFactory();
283         } else {
284             ntlmSchemeProvider = new DavMailNTLMSchemeFactory();
285         }
286         registryBuilder.register(AuthSchemes.NTLM, ntlmSchemeProvider)
287                 .register(AuthSchemes.BASIC, new BasicSchemeFactory())
288                 .register(AuthSchemes.DIGEST, new DigestSchemeFactory());
289         if (Settings.getBooleanProperty("davmail.enableKerberos")) {
290             registryBuilder.register(AuthSchemes.SPNEGO, new DavMailSPNegoSchemeFactory());
291         }
292 
293         return registryBuilder.build();
294     }
295 
296     private RequestConfig getRequestConfig() {
297         HashSet<String> authSchemes = new HashSet<>();
298         if (Settings.getBooleanProperty("davmail.enableKerberos")) {
299             authSchemes.add(AuthSchemes.SPNEGO);
300             authSchemes.add(AuthSchemes.KERBEROS);
301         } else {
302             authSchemes.add(AuthSchemes.NTLM);
303             authSchemes.add(AuthSchemes.BASIC);
304             authSchemes.add(AuthSchemes.DIGEST);
305         }
306         return RequestConfig.custom()
307                 .setCookieSpec(CookieSpecs.STANDARD)
308                 // socket connect timeout
309                 .setConnectTimeout(Settings.getIntProperty("davmail.exchange.connectionTimeout", 10) * 1000)
310                 // inactivity timeout
311                 .setSocketTimeout(Settings.getIntProperty("davmail.exchange.soTimeout", 120) * 1000)
312                 .setTargetPreferredAuthSchemes(authSchemes)
313                 .build();
314     }
315 
316     private void parseUserName(String username) {
317         if (username != null) {
318             int pipeIndex = username.indexOf("|");
319             if (pipeIndex >= 0) {
320                 userid = username.substring(0, pipeIndex);
321                 userEmail = username.substring(pipeIndex + 1);
322             } else {
323                 userid = username;
324                 userEmail = username;
325             }
326             // separate domain name
327             int backSlashIndex = userid.indexOf('\\');
328             if (backSlashIndex >= 0) {
329                 // separate domain from username in credentials
330                 domain = userid.substring(0, backSlashIndex);
331                 userid = userid.substring(backSlashIndex + 1);
332             } else if (userid.contains("@")) {
333                 // no need for domain name with userPrincipalName
334                 domain = "";
335             } else {
336                 domain = Settings.getProperty("davmail.defaultDomain", "");
337             }
338         }
339     }
340 
341     /**
342      * Retrieve Proxy Selector
343      *
344      * @param uri target uri
345      * @return proxy selector
346      */
347     private static List<Proxy> getProxyForURI(java.net.URI uri) {
348         LOGGER.debug("get Default proxy selector");
349         ProxySelector proxySelector = ProxySelector.getDefault();
350         LOGGER.debug("getProxyForURI(" + uri + ')');
351         List<Proxy> proxies = proxySelector.select(uri);
352         LOGGER.debug("got system proxies:" + proxies);
353         return proxies;
354     }
355 
356     protected static boolean isNoProxyFor(java.net.URI uri) {
357         final String noProxyFor = Settings.getProperty("davmail.noProxyFor");
358         if (noProxyFor != null) {
359             final String uriHost = uri.getHost().toLowerCase();
360             final String[] domains = noProxyFor.toLowerCase().split(",\\s*");
361             for (String domain : domains) {
362                 if (uriHost.endsWith(domain)) {
363                     return true;
364                 }
365             }
366         }
367         return false;
368     }
369 
370     public void startEvictorThread() {
371         DavMailIdleConnectionEvictor.addConnectionManager(connectionManager);
372     }
373 
374     @Override
375     public void close() {
376         DavMailIdleConnectionEvictor.removeConnectionManager(connectionManager);
377         try {
378             httpClient.close();
379         } catch (IOException e) {
380             LOGGER.warn("Exception closing http client", e);
381         }
382     }
383 
384     public static void close(HttpClientAdapter httpClientAdapter) {
385         if (httpClientAdapter != null) {
386             httpClientAdapter.close();
387         }
388     }
389 
390     /**
391      * Execute request, do not follow redirects.
392      * if request is an instance of ResponseHandler, process and close response
393      *
394      * @param request Http request
395      * @return Http response
396      * @throws IOException on error
397      */
398     public CloseableHttpResponse execute(HttpRequestBase request) throws IOException {
399         return execute(request, null);
400     }
401 
402     /**
403      * Execute request, do not follow redirects.
404      * if request is an instance of ResponseHandler, process and close response
405      *
406      * @param request Http request
407      * @param context Http request context
408      * @return Http response
409      * @throws IOException on error
410      */
411     public CloseableHttpResponse execute(HttpRequestBase request, HttpClientContext context) throws IOException {
412         // make sure request path is absolute
413         handleURI(request);
414         // execute request and return response
415         return httpClient.execute(request, context);
416     }
417 
418     /**
419      * fix relative uri and update current uri.
420      *
421      * @param request http request
422      */
423     private void handleURI(HttpRequestBase request) {
424         URI requestURI = request.getURI();
425         if (!requestURI.isAbsolute()) {
426             request.setURI(URIUtils.resolve(uri, requestURI));
427         }
428         uri = request.getURI();
429     }
430 
431     public ResponseWrapper executeFollowRedirect(PostRequest request) throws IOException {
432         ResponseWrapper responseWrapper = request;
433         LOGGER.debug(request.getMethod() + " " + request.getURI().toString());
434         LOGGER.debug(request.getParameters());
435 
436         int count = 0;
437         int maxRedirect = Settings.getIntProperty("davmail.httpMaxRedirects", MAX_REDIRECTS);
438 
439         executePostRequest(request);
440         URI redirectLocation = request.getRedirectLocation();
441 
442         while (count++ < maxRedirect && redirectLocation != null) {
443             LOGGER.debug("Redirect " + request.getURI() + " to " + redirectLocation);
444             // replace uri with target location
445             responseWrapper = new GetRequest(redirectLocation);
446             executeGetRequest((GetRequest) responseWrapper);
447             redirectLocation = ((GetRequest) responseWrapper).getRedirectLocation();
448         }
449 
450         return responseWrapper;
451     }
452 
453     public GetRequest executeFollowRedirect(GetRequest request) throws IOException {
454         GetRequest result = request;
455         LOGGER.debug(request.getMethod() + " " + request.getURI().toString());
456 
457         int count = 0;
458         int maxRedirect = Settings.getIntProperty("davmail.httpMaxRedirects", MAX_REDIRECTS);
459 
460         executeGetRequest(request);
461         URI redirectLocation = request.getRedirectLocation();
462 
463         while (count++ < maxRedirect && redirectLocation != null) {
464             LOGGER.debug("Redirect " + request.getURI() + " to " + redirectLocation);
465             // replace uri with target location
466             result = new GetRequest(redirectLocation);
467             executeGetRequest(result);
468             redirectLocation = result.getRedirectLocation();
469         }
470 
471         return result;
472     }
473 
474     /**
475      * Execute get request and return response body as string.
476      *
477      * @param getRequest get request
478      * @return response body
479      * @throws IOException on error
480      */
481     public String executeGetRequest(GetRequest getRequest) throws IOException {
482         handleURI(getRequest);
483         String responseBodyAsString;
484         try (CloseableHttpResponse response = execute(getRequest)) {
485             responseBodyAsString = getRequest.handleResponse(response);
486         }
487         return responseBodyAsString;
488     }
489 
490     /**
491      * Execute post request and return response body as string.
492      *
493      * @param postRequest post request
494      * @return response body
495      * @throws IOException on error
496      */
497     public String executePostRequest(PostRequest postRequest) throws IOException {
498         handleURI(postRequest);
499         String responseBodyAsString;
500         try (CloseableHttpResponse response = execute(postRequest)) {
501             responseBodyAsString = postRequest.handleResponse(response);
502         }
503         return responseBodyAsString;
504     }
505 
506     public JSONObject executeRestRequest(RestRequest restRequest) throws IOException {
507         handleURI(restRequest);
508         JSONObject responseBody;
509         try (CloseableHttpResponse response = execute(restRequest)) {
510             responseBody = restRequest.handleResponse(response);
511         }
512         return responseBody;
513     }
514 
515     /**
516      * Execute WebDav request
517      *
518      * @param request WebDav request
519      * @return multistatus response
520      * @throws IOException on error
521      */
522     public MultiStatus executeDavRequest(BaseDavRequest request) throws IOException {
523         handleURI(request);
524         MultiStatus multiStatus = null;
525         try (CloseableHttpResponse response = execute(request)) {
526             request.checkSuccess(response);
527             if (response.getStatusLine().getStatusCode() == HttpStatus.SC_MULTI_STATUS) {
528                 multiStatus = request.getResponseBodyAsMultiStatus(response);
529             }
530         } catch (DavException e) {
531             LOGGER.error(e.getMessage(), e);
532             throw new IOException(e.getErrorCode() + " " + e.getStatusPhrase(), e);
533         }
534         return multiStatus;
535     }
536 
537     /**
538      * Execute Exchange WebDav request
539      *
540      * @param request WebDav request
541      * @return multistatus response
542      * @throws IOException on error
543      */
544     public MultiStatusResponse[] executeDavRequest(ExchangeDavRequest request) throws IOException {
545         handleURI(request);
546         MultiStatusResponse[] responses;
547         try (CloseableHttpResponse response = execute(request)) {
548             List<MultiStatusResponse> responseList = request.handleResponse(response);
549             // TODO check error handling
550             //request.checkSuccess(response);
551             responses = responseList.toArray(new MultiStatusResponse[0]);
552         }
553         return responses;
554     }
555 
556 
557     /**
558      * Execute webdav search method.
559      *
560      * @param path            <i>encoded</i> searched folder path
561      * @param searchStatement (SQL like) search statement
562      * @param maxCount        max item count
563      * @return Responses enumeration
564      * @throws IOException on error
565      */
566     public MultiStatusResponse[] executeSearchRequest(String path, String searchStatement, int maxCount) throws IOException {
567         ExchangeSearchRequest searchRequest = new ExchangeSearchRequest(path, searchStatement);
568         if (maxCount > 0) {
569             searchRequest.setHeader("Range", "rows=0-" + (maxCount - 1));
570         }
571         return executeDavRequest(searchRequest);
572     }
573 
574     public static boolean isRedirect(HttpResponse response) {
575         return isRedirect(response.getStatusLine().getStatusCode());
576     }
577 
578     /**
579      * Check if status is a redirect (various 30x values).
580      *
581      * @param status Http status
582      * @return true if status is a redirect
583      */
584     public static boolean isRedirect(int status) {
585         return status == HttpStatus.SC_MOVED_PERMANENTLY
586                 || status == HttpStatus.SC_MOVED_TEMPORARILY
587                 || status == HttpStatus.SC_SEE_OTHER
588                 || status == HttpStatus.SC_TEMPORARY_REDIRECT;
589     }
590 
591     /**
592      * Get redirect location from header.
593      *
594      * @param response Http response
595      * @return URI target location
596      */
597     public static URI getRedirectLocation(HttpResponse response) {
598         Header location = response.getFirstHeader("Location");
599         if (isRedirect(response.getStatusLine().getStatusCode()) && location != null) {
600             return URI.create(location.getValue());
601         }
602         return null;
603     }
604 
605     public void setCredentials(String username, String password) {
606         parseUserName(username);
607         if (userid != null && password != null) {
608             LOGGER.debug("Creating NTCredentials for user " + userid + " workstation " + WORKSTATION_NAME + " domain " + domain);
609             NTCredentials credentials = new NTCredentials(userid, password, WORKSTATION_NAME, domain);
610             provider.setCredentials(AuthScope.ANY, credentials);
611         }
612     }
613 
614     public List<Cookie> getCookies() {
615         return cookieStore.getCookies();
616     }
617 
618     public void addCookie(Cookie cookie) {
619         cookieStore.addCookie(cookie);
620     }
621 
622     public String getUserAgent() {
623         return Settings.getUserAgent();
624     }
625 
626     public static HttpResponseException buildHttpResponseException(HttpRequestBase request, HttpResponse response) {
627         return buildHttpResponseException(request, response.getStatusLine());
628     }
629 
630     /**
631      * Build Http Exception from method status
632      *
633      * @param method Http Method
634      * @return Http Exception
635      */
636     public static HttpResponseException buildHttpResponseException(HttpRequestBase method, StatusLine statusLine) {
637         int status = statusLine.getStatusCode();
638         StringBuilder message = new StringBuilder();
639         message.append(status).append(' ').append(statusLine.getReasonPhrase());
640         message.append(" at ").append(method.getURI());
641         if (method instanceof HttpCopy || method instanceof HttpMove) {
642             message.append(" to ").append(method.getFirstHeader("Destination"));
643         }
644         // 440 means forbidden on Exchange
645         if (status == 440) {
646             return new LoginTimeoutException(message.toString());
647         } else if (status == HttpStatus.SC_FORBIDDEN) {
648             return new HttpForbiddenException(message.toString());
649         } else if (status == HttpStatus.SC_NOT_FOUND) {
650             return new HttpNotFoundException(message.toString());
651         } else if (status == HttpStatus.SC_PRECONDITION_FAILED) {
652             return new HttpPreconditionFailedException(message.toString());
653         } else if (status == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
654             return new HttpServerErrorException(message.toString());
655         } else {
656             return new HttpResponseException(status, message.toString());
657         }
658     }
659 
660 }