1717import com .clickhouse .client .api .transport .Endpoint ;
1818import com .clickhouse .client .api .transport .internal .TransportRequest ;
1919import com .clickhouse .client .api .transport .internal .TransportResponse ;
20- import com .clickhouse .client .config .ClickHouseDefaultSslContextProvider ;
2120import com .clickhouse .data .ClickHouseFormat ;
2221import net .jpountz .lz4 .LZ4Factory ;
2322import org .apache .commons .compress .compressors .CompressorStreamFactory ;
4645import org .apache .hc .core5 .http .HttpHeaders ;
4746import org .apache .hc .core5 .http .HttpHost ;
4847import org .apache .hc .core5 .http .HttpRequest ;
48+ import org .apache .hc .core5 .http .HttpResponse ;
4949import org .apache .hc .core5 .http .HttpStatus ;
5050import org .apache .hc .core5 .http .NoHttpResponseException ;
5151import org .apache .hc .core5 .http .ProtocolException ;
@@ -369,10 +369,7 @@ public CloseableHttpClient createHttpClient(boolean initSslContext, Map<String,
369369 * @return exception object with server code
370370 */
371371 public Exception readError (HttpPost req , ClassicHttpResponse httpResponse ) {
372- final Header serverQueryIdHeader = httpResponse .getFirstHeader (ClickHouseHttpProto .HEADER_QUERY_ID );
373- final Header clientQueryIdHeader = req .getFirstHeader (ClickHouseHttpProto .HEADER_QUERY_ID );
374- final Header queryHeader = Stream .of (serverQueryIdHeader , clientQueryIdHeader ).filter (Objects ::nonNull ).findFirst ().orElse (null );
375- final String queryId = queryHeader == null ? "" : queryHeader .getValue ();
372+ final String queryId = getQueryId (httpResponse , req );
376373 int serverCode = getHeaderInt (httpResponse .getFirstHeader (ClickHouseHttpProto .HEADER_EXCEPTION_CODE ), 0 );
377374 try {
378375 return serverCode > 0 ? readClickHouseError (httpResponse .getEntity (), serverCode , queryId , httpResponse .getCode ()) :
@@ -608,11 +605,6 @@ private static final class TransportResponseImpl implements TransportResponse {
608605 this .delegate = delegate ;
609606 }
610607
611- @ Override
612- public int getStatusCode () {
613- return 0 ;
614- }
615-
616608 @ Override
617609 public ClickHouseFormat getDataFormat () {
618610 Header formatHeader = delegate .getFirstHeader (ClickHouseHttpProto .HEADER_FORMAT );
@@ -632,6 +624,7 @@ public String getQueryId() {
632624 }
633625
634626 @ Override
627+ @ SuppressWarnings ("unchecked" )
635628 public <T > T getDelegate () {
636629 return (T ) delegate ;
637630 }
@@ -680,6 +673,7 @@ private ClassicHttpResponse doPostRequest(Map<String, Object> requestConfig, Htt
680673 doPoolVent ();
681674
682675 ClassicHttpResponse httpResponse = null ;
676+ boolean closeResponse = true ;
683677 HttpContext context = createRequestHttpContext (requestConfig );
684678 try {
685679 httpResponse = httpClient .executeOpen (null , req , context );
@@ -688,35 +682,58 @@ private ClassicHttpResponse doPostRequest(Map<String, Object> requestConfig, Htt
688682 httpResponse .getCode (),
689683 requestConfig ));
690684
691- if (httpResponse .getCode () == HttpStatus .SC_PROXY_AUTHENTICATION_REQUIRED ) {
692- throw new ClientMisconfigurationException ("Proxy authentication required. Please check your proxy settings." );
693- } else if (httpResponse .getCode () == HttpStatus .SC_BAD_GATEWAY ) {
694- httpResponse .close ();
695- throw new ClientException ("Server returned '502 Bad gateway'. Check network and proxy settings." );
696- } else if (httpResponse .getCode () >= HttpStatus .SC_BAD_REQUEST || httpResponse .containsHeader (ClickHouseHttpProto .HEADER_EXCEPTION_CODE )) {
697- try {
698- throw readError (req , httpResponse );
699- } finally {
700- httpResponse .close ();
701- }
685+ if (httpResponse .containsHeader (ClickHouseHttpProto .HEADER_EXCEPTION_CODE )) {
686+ throw readError (req , httpResponse );
702687 }
703- return httpResponse ;
704688
689+ int statusCode = httpResponse .getCode ();
690+ switch (statusCode ) {
691+ case HttpStatus .SC_OK :
692+ closeResponse = false ;
693+ return httpResponse ;
694+ case HttpStatus .SC_PROXY_AUTHENTICATION_REQUIRED :
695+ throw new ClientMisconfigurationException ("Proxy authentication required. Please check your proxy settings." );
696+ case HttpStatus .SC_BAD_GATEWAY :
697+ throw new ClientException ("Server returned '502 Bad gateway'. Check network and proxy settings." );
698+ case HttpStatus .SC_SERVICE_UNAVAILABLE :
699+ throw new ServerException (0 , "Server returned '503 Service Unavailable'. Check network settings." ,
700+ HttpStatus .SC_SERVICE_UNAVAILABLE , getQueryId (httpResponse , req ));
701+ case HttpStatus .SC_BAD_REQUEST :
702+ case HttpStatus .SC_UNAUTHORIZED :
703+ case HttpStatus .SC_FORBIDDEN :
704+ case HttpStatus .SC_SERVER_ERROR :
705+ case HttpStatus .SC_NOT_FOUND :
706+ // ClickHouse usually uses SC_BAD_REQUEST and SC_SERVER_ERROR to return error.
707+ // SC_UNAUTHORIZED, SC_FORBIDDEN is for authentication
708+ // SC_NOT_FOUND can be returned by ClickHouse when path doesn't match database, but also by proxy
709+ // others we cannot handle properly
710+ throw readError (req , httpResponse );
711+ default :
712+ throw new ClientException ("Unexpected result status " + statusCode );
713+ }
705714 } catch (UnknownHostException e ) {
706- ClientUtils .quiteClose (httpResponse , LOG );
707715 LOG .warn ("Host '{}' unknown" , req .getAuthority ());
708716 throw e ;
709717 } catch (ConnectException | NoRouteToHostException e ) {
710- ClientUtils .quiteClose (httpResponse , LOG );
711718 LOG .warn ("Failed to connect to '{}': {}" , req .getAuthority (), e .getMessage ());
712719 throw e ;
713720 } catch (Exception e ) {
714- ClientUtils .quiteClose (httpResponse , LOG );
715721 LOG .debug ("Failed to execute request to '{}': {}" , req .getAuthority (), e .getMessage (), e );
716722 throw e ;
723+ } finally {
724+ if (closeResponse ) {
725+ ClientUtils .quietClose (httpResponse , LOG );
726+ }
717727 }
718728 }
719729
730+ private String getQueryId (HttpResponse httpResponse , HttpPost httpRequest ) {
731+ final Header serverQueryIdHeader = httpResponse .getFirstHeader (ClickHouseHttpProto .HEADER_QUERY_ID );
732+ final Header clientQueryIdHeader = httpRequest .getFirstHeader (ClickHouseHttpProto .HEADER_QUERY_ID );
733+ final Header queryHeader = Stream .of (serverQueryIdHeader , clientQueryIdHeader ).filter (Objects ::nonNull ).findFirst ().orElse (null );
734+ return queryHeader == null ? "" : queryHeader .getValue ();
735+ }
736+
720737 private static final ContentType CONTENT_TYPE = ContentType .create (ContentType .TEXT_PLAIN .getMimeType (), "UTF-8" );
721738
722739 private void addHeaders (HttpPost req , Map <String , Object > requestConfig ) {
0 commit comments