ConnettoreHTTPCORE.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.pdd.core.connettori;

  21. import java.io.InputStream;
  22. import java.net.URI;
  23. import java.net.URL;
  24. import java.util.ArrayList;
  25. import java.util.HashMap;
  26. import java.util.Iterator;
  27. import java.util.List;
  28. import java.util.Map;

  29. import javax.net.ssl.HostnameVerifier;
  30. import javax.net.ssl.SSLSocketFactory;

  31. import org.apache.commons.lang.StringUtils;
  32. import org.apache.http.Header;
  33. import org.apache.http.HeaderElement;
  34. import org.apache.http.HeaderElementIterator;
  35. import org.apache.http.HttpEntity;
  36. import org.apache.http.HttpResponse;
  37. import org.apache.http.client.HttpClient;
  38. import org.apache.http.client.config.RequestConfig;
  39. import org.apache.http.client.methods.HttpDelete;
  40. import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
  41. import org.apache.http.client.methods.HttpGet;
  42. import org.apache.http.client.methods.HttpHead;
  43. import org.apache.http.client.methods.HttpOptions;
  44. import org.apache.http.client.methods.HttpPatch;
  45. import org.apache.http.client.methods.HttpPost;
  46. import org.apache.http.client.methods.HttpRequestBase;
  47. import org.apache.http.client.methods.HttpTrace;
  48. import org.apache.http.config.Registry;
  49. import org.apache.http.config.RegistryBuilder;
  50. import org.apache.http.conn.ConnectionKeepAliveStrategy;
  51. import org.apache.http.conn.socket.ConnectionSocketFactory;
  52. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
  53. import org.apache.http.entity.ByteArrayEntity;
  54. import org.apache.http.entity.FileEntity;
  55. import org.apache.http.entity.InputStreamEntity;
  56. import org.apache.http.impl.client.DefaultClientConnectionReuseStrategy;
  57. import org.apache.http.impl.client.HttpClientBuilder;
  58. import org.apache.http.impl.client.HttpClients;
  59. import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
  60. import org.apache.http.message.BasicHeaderElementIterator;
  61. import org.apache.http.protocol.HTTP;
  62. import org.apache.http.protocol.HttpContext;
  63. import org.apache.http.util.EntityUtils;
  64. import org.openspcoop2.core.config.ResponseCachingConfigurazione;
  65. import org.openspcoop2.core.constants.CostantiConnettori;
  66. import org.openspcoop2.core.constants.TransferLengthModes;
  67. import org.openspcoop2.core.transazioni.constants.TipoMessaggio;
  68. import org.openspcoop2.message.OpenSPCoop2RestMessage;
  69. import org.openspcoop2.message.OpenSPCoop2SoapMessage;
  70. import org.openspcoop2.message.constants.Costanti;
  71. import org.openspcoop2.message.constants.MessageType;
  72. import org.openspcoop2.message.soap.TunnelSoapUtils;
  73. import org.openspcoop2.pdd.mdb.ConsegnaContenutiApplicativi;
  74. import org.openspcoop2.utils.NameValue;
  75. import org.openspcoop2.utils.UtilsException;
  76. import org.openspcoop2.utils.date.DateManager;
  77. import org.openspcoop2.utils.io.Base64Utilities;
  78. import org.openspcoop2.utils.io.DumpByteArrayOutputStream;
  79. import org.openspcoop2.utils.transport.TransportUtils;
  80. import org.openspcoop2.utils.transport.http.HttpBodyParameters;
  81. import org.openspcoop2.utils.transport.http.HttpConstants;
  82. import org.openspcoop2.utils.transport.http.HttpRequestMethod;
  83. import org.openspcoop2.utils.transport.http.HttpUtilities;
  84. import org.openspcoop2.utils.transport.http.RFC2047Utilities;
  85. import org.openspcoop2.utils.transport.http.SSLUtilities;
  86. import org.openspcoop2.utils.transport.http.WrappedLogSSLSocketFactory;

  87. /**
  88.  * Connettore che utilizza la libreria httpcore
  89.  *
  90.  *
  91.  * @author Poli Andrea (apoli@link.it)
  92.  * @author $Author$
  93.  * @version $Rev$, $Date$
  94.  */
  95. public class ConnettoreHTTPCORE extends ConnettoreBaseHTTP {

  96.     public static final String ENDPOINT_TYPE = "httpcore";
  97.    
  98.    
  99.     private static boolean USE_POOL = true;
  100.    
  101.     private HttpEntity httpEntityResponse = null;
  102.     private HttpClient httpClient = null;
  103.        
  104.     private HttpRequestBase httpRequest;
  105.    
  106.    
  107.     /* Costruttori */
  108.     public ConnettoreHTTPCORE(){
  109.         this.connettoreHttps = false;
  110.     }
  111.     public ConnettoreHTTPCORE(boolean https){
  112.         this.connettoreHttps = https;
  113.     }
  114.    
  115.    
  116.     private static Map<String, PoolingHttpClientConnectionManager> cmMap = new HashMap<String, PoolingHttpClientConnectionManager>();
  117.     private static synchronized void initialize(String key, SSLConnectionSocketFactory sslConnectionSocketFactory){
  118.         if(!ConnettoreHTTPCORE.cmMap.containsKey(key)){
  119.                        
  120.             PoolingHttpClientConnectionManager cm = null;
  121.             if(sslConnectionSocketFactory!=null) {
  122.                 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
  123.                         .<ConnectionSocketFactory> create().register("https", sslConnectionSocketFactory)
  124.                         .build();
  125.                 cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
  126.             }
  127.             else {
  128.                 cm = new PoolingHttpClientConnectionManager();
  129.             }
  130.             // Increase max total connection to 200
  131.             cm.setMaxTotal(200);
  132.             // Increase default max connection per route to 20
  133.             cm.setDefaultMaxPerRoute(5);
  134.             // Increase max connections for localhost:80 to 50
  135.             //HttpHost localhost = new HttpHost("locahost", 80);
  136.             //cm.setMaxPerRoute(new HttpRoute(localhost), 50);
  137.              
  138.             ConnettoreHTTPCORE.cmMap.put(key, cm);
  139.         }
  140.     }
  141.    
  142.     private HttpClient buildHttpClient(ConnectionKeepAliveStrategy keepAliveStrategy, SSLSocketFactory sslSocketFactory, boolean usePool) throws UtilsException{
  143.        
  144.         HttpClientBuilder httpClientBuilder = HttpClients.custom();
  145.            
  146.         // Imposta Contesto SSL se attivo
  147.        
  148.         String key = "default";
  149.         if(this.sslContextProperties!=null){
  150.             key = this.sslContextProperties.toString();
  151.         }
  152.        
  153.         SSLConnectionSocketFactory sslConnectionSocketFactory = null;
  154.         if(this.sslContextProperties!=null &&
  155.                 (!usePool || !ConnettoreHTTPCORE.cmMap.containsKey(key))){
  156.             if(this.debug) {
  157.                 String clientCertificateConfigurated = this.sslContextProperties.getKeyStoreLocation();
  158.                 sslSocketFactory = new WrappedLogSSLSocketFactory(sslSocketFactory,
  159.                         this.logger.getLogger(), this.logger.buildMsg(""),
  160.                         clientCertificateConfigurated);
  161.             }      
  162.            
  163.             StringBuilder bfLog = new StringBuilder();
  164.             HostnameVerifier hostnameVerifier = SSLUtilities.generateHostnameVerifier(this.sslContextProperties, bfLog,
  165.                     this.logger.getLogger(), this.loader);
  166.             if(this.debug)
  167.                 this.logger.debug(bfLog.toString());
  168.            
  169.             if(hostnameVerifier==null) {
  170.                 hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
  171.             }
  172.             sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslSocketFactory, hostnameVerifier);
  173.         }
  174.        
  175.         if(usePool) {
  176.                        
  177.             // Caso con pool
  178.             if(!ConnettoreHTTPCORE.cmMap.containsKey(key)){
  179.                 ConnettoreHTTPCORE.initialize(key, sslConnectionSocketFactory);
  180.             }
  181.            
  182.             PoolingHttpClientConnectionManager cm = ConnettoreHTTPCORE.cmMap.get(key);
  183.            
  184.             //System.out.println("-----GET CONNECTION [START] ----");
  185.             //System.out.println("PRIMA CLOSE AVAILABLE["+cm.getTotalStats().getAvailable()+"] LEASED["
  186.             //      +cm.getTotalStats().getLeased()+"] MAX["+cm.getTotalStats().getMax()+"] PENDING["+cm.getTotalStats().getPending()+"]");
  187.             // BLOCKED ConnettoreHTTPCORE.cm.closeExpiredConnections();
  188.             // BLOCKED ConnettoreHTTPCORE.cm.closeIdleConnections(30, java.util.concurrent.TimeUnit.SECONDS);
  189.             //System.out.println("DOPO CLOSE AVAILABLE["+cm.getTotalStats().getAvailable()+"] LEASED["
  190.             //      +cm.getTotalStats().getLeased()+"] MAX["+cm.getTotalStats().getMax()+"] PENDING["+cm.getTotalStats().getPending()+"]");
  191.             httpClientBuilder.setConnectionManager(cm);
  192.         }
  193.         else {
  194.             if(sslConnectionSocketFactory!=null) {
  195.                 httpClientBuilder.setSSLSocketFactory(sslConnectionSocketFactory);      
  196.             }
  197.         }
  198.        
  199.         DefaultClientConnectionReuseStrategy defaultClientConnectionReuseStrategy = new DefaultClientConnectionReuseStrategy();
  200.         httpClientBuilder.setConnectionReuseStrategy(defaultClientConnectionReuseStrategy);
  201.        
  202.         if(keepAliveStrategy!=null){
  203.             httpClientBuilder.setKeepAliveStrategy(keepAliveStrategy);
  204.         }
  205.                
  206.         //System.out.println("PRESA LA CONNESSIONE AVAILABLE["+cm.getTotalStats().getAvailable()+"] LEASED["
  207.         //      +cm.getTotalStats().getLeased()+"] MAX["+cm.getTotalStats().getMax()+"] PENDING["+cm.getTotalStats().getPending()+"]");
  208.         //System.out.println("-----GET CONNECTION [END] ----");
  209.        
  210.         return httpClientBuilder.build();
  211.     }
  212.    
  213.    
  214.     @Override
  215.     protected boolean initializePreSend(ResponseCachingConfigurazione responseCachingConfig, ConnettoreMsg request) {
  216.        
  217.         if(this.initialize(request, true, responseCachingConfig)==false){
  218.             return false;
  219.         }
  220.        
  221.         return true;
  222.        
  223.     }
  224.    
  225.     @Override
  226.     protected boolean send(ConnettoreMsg request) {
  227.        
  228.         // HTTPS
  229.         try{
  230.             this.setSSLContext();
  231.         }catch(Exception e){
  232.             this.eccezioneProcessamento = e;
  233.             this.logger.error("[HTTPS error]"+ this.readExceptionMessageFromException(e),e);
  234.             this.errore = "[HTTPS error]"+ this.readExceptionMessageFromException(e);
  235.             return false;
  236.         }
  237.        
  238.         int connectionTimeout = -1;
  239.         boolean connectionTimeoutConfigurazioneGlobale = true;
  240.         int readConnectionTimeout = -1;
  241.         boolean readConnectionTimeoutConfigurazioneGlobale = true;
  242.         try{
  243.            
  244.             // Creazione URL
  245.             if(this.debug)
  246.                 this.logger.debug("Creazione URL...");
  247.             this.buildLocation();      
  248.             if(this.debug)
  249.                 this.logger.debug("Creazione URL ["+this.location+"]...");
  250.             URL url = new URL( this.location );
  251.            
  252.            
  253.             // Keep-alive
  254.             ConnectionKeepAliveStrategy keepAliveStrategy = null; //new ConnectionKeepAliveStrategyCustom();
  255.            
  256.            
  257.            
  258.             // Collezione header di trasporto per dump
  259.             Map<String, List<String>> propertiesTrasportoDebug = null;
  260.             if(this.isDumpBinarioRichiesta()) {
  261.                 propertiesTrasportoDebug = new HashMap<>();
  262.             }

  263.            
  264.             // Creazione Connessione
  265.             if(this.debug)
  266.                 this.logger.info("Creazione connessione alla URL ["+this.location+"]...",false);
  267.             this.httpClient = buildHttpClient(keepAliveStrategy, buildSSLContextFactory(), ConnettoreHTTPCORE.USE_POOL);
  268.            
  269.             // HttpMethod
  270.             if(this.httpMethod==null){
  271.                 throw new Exception("HttpRequestMethod non definito");
  272.             }
  273.             this.httpRequest = null;
  274.             switch (this.httpMethod) {
  275.                 case GET:
  276.                     this.httpRequest = new HttpGet(url.toString());
  277.                     break;
  278.                 case DELETE:
  279.                     this.httpRequest = new HttpDelete(url.toString());
  280.                     break;
  281.                 case HEAD:
  282.                     this.httpRequest = new HttpHead(url.toString());
  283.                     break;
  284.                 case POST:
  285.                     this.httpRequest = new HttpPost(url.toString());
  286.                     break;
  287.                 case PUT:
  288.                     this.httpRequest = new HttpPost(url.toString());
  289.                     break;
  290.                 case OPTIONS:
  291.                     this.httpRequest = new HttpOptions(url.toString());
  292.                     break;
  293.                 case TRACE:
  294.                     this.httpRequest = new HttpTrace(url.toString());
  295.                     break;
  296.                 case PATCH:
  297.                     this.httpRequest = new HttpPatch(url.toString());
  298.                     break;  
  299.                 default:
  300.                     this.httpRequest = new CustomHttpEntity(this.httpMethod, url.toString());
  301.                     break;
  302.             }
  303.             if(this.httpMethod==null){
  304.                 throw new Exception("HttpRequest non definito ?");
  305.             }
  306.             RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
  307.            
  308.            
  309.            
  310.             // Tipologia di servizio
  311.             OpenSPCoop2SoapMessage soapMessageRequest = null;
  312.             MessageType requestMessageType = this.requestMsg.getMessageType();
  313.             if(this.debug)
  314.                 this.logger.debug("Tipologia Servizio: "+this.requestMsg.getServiceBinding());
  315.             if(this.isSoap){
  316.                 soapMessageRequest = this.requestMsg.castAsSoap();
  317.             }
  318.            
  319.            
  320.            
  321.             // Alcune implementazioni richiedono di aggiornare il Content-Type
  322.             this.requestMsg.updateContentType();
  323.            
  324.                        
  325.            
  326.             // Impostazione Content-Type della Spedizione su HTTP
  327.            
  328.             if(this.debug)
  329.                 this.logger.debug("Impostazione content type...");
  330.             String contentTypeRichiesta = null;
  331.             if(this.isSoap){
  332.                 if(this.sbustamentoSoap && soapMessageRequest.countAttachments()>0 && TunnelSoapUtils.isTunnelOpenSPCoopSoap(soapMessageRequest)){
  333.                     contentTypeRichiesta = TunnelSoapUtils.getContentTypeTunnelOpenSPCoopSoap(soapMessageRequest.getSOAPBody());
  334.                 }else{
  335.                     contentTypeRichiesta = this.requestMsg.getContentType();
  336.                 }
  337.                 if(contentTypeRichiesta==null){
  338.                     throw new Exception("Content-Type del messaggio da spedire non definito");
  339.                 }
  340.             }
  341.             else{
  342.                 contentTypeRichiesta = this.requestMsg.getContentType();
  343.                 // Content-Type non obbligatorio in REST
  344.             }
  345.             if(this.debug)
  346.                 this.logger.info("Impostazione http Content-Type ["+contentTypeRichiesta+"]",false);
  347.             if(contentTypeRichiesta!=null){
  348.                 this.setRequestHeader(HttpConstants.CONTENT_TYPE, contentTypeRichiesta, propertiesTrasportoDebug);
  349.             }
  350.            
  351.            
  352.            
  353.             // Impostazione transfer-length
  354.             if(this.debug)
  355.                 this.logger.debug("Impostazione transfer-length...");
  356.             boolean transferEncodingChunked = false;
  357.             TransferLengthModes tlm = null;
  358.             int chunkLength = -1;
  359.             if(ConsegnaContenutiApplicativi.ID_MODULO.equals(this.idModulo)){
  360.                 tlm = this.openspcoopProperties.getTransferLengthModes_consegnaContenutiApplicativi();
  361.                 chunkLength = this.openspcoopProperties.getChunkLength_consegnaContenutiApplicativi();
  362.             }
  363.             else{
  364.                 // InoltroBuste e InoltroRisposte
  365.                 tlm = this.openspcoopProperties.getTransferLengthModes_inoltroBuste();
  366.                 chunkLength = this.openspcoopProperties.getChunkLength_inoltroBuste();
  367.             }
  368.             transferEncodingChunked = TransferLengthModes.TRANSFER_ENCODING_CHUNKED.equals(tlm);
  369.             if(transferEncodingChunked){
  370.                 //this.httpConn.setChunkedStreamingMode(chunkLength);
  371.             }
  372.             if(this.debug)
  373.                 this.logger.info("Impostazione transfer-length effettuata (chunkLength:"+chunkLength+"): "+tlm,false);
  374.            
  375.            
  376.            
  377.             // Impostazione timeout
  378.             if(this.debug)
  379.                 this.logger.debug("Impostazione timeout...");
  380.             if(this.properties.get(CostantiConnettori.CONNETTORE_CONNECTION_TIMEOUT)!=null){
  381.                 try{
  382.                     connectionTimeout = Integer.parseInt(this.properties.get(CostantiConnettori.CONNETTORE_CONNECTION_TIMEOUT));
  383.                     connectionTimeoutConfigurazioneGlobale = this.properties.containsKey(CostantiConnettori.CONNETTORE_CONNECTION_TIMEOUT_GLOBALE);
  384.                 }catch(Exception e){
  385.                     this.logger.error("Parametro '"+CostantiConnettori.CONNETTORE_CONNECTION_TIMEOUT+"' errato",e);
  386.                 }
  387.             }
  388.             if(connectionTimeout==-1){
  389.                 connectionTimeout = HttpUtilities.HTTP_CONNECTION_TIMEOUT;
  390.             }
  391.             if(this.properties.get(CostantiConnettori.CONNETTORE_READ_CONNECTION_TIMEOUT)!=null){
  392.                 try{
  393.                     readConnectionTimeout = Integer.parseInt(this.properties.get(CostantiConnettori.CONNETTORE_READ_CONNECTION_TIMEOUT));
  394.                     readConnectionTimeoutConfigurazioneGlobale = this.properties.containsKey(CostantiConnettori.CONNETTORE_READ_CONNECTION_TIMEOUT_GLOBALE);
  395.                 }catch(Exception e){
  396.                     this.logger.error("Parametro '"+CostantiConnettori.CONNETTORE_READ_CONNECTION_TIMEOUT+"' errato",e);
  397.                 }
  398.             }
  399.             if(readConnectionTimeout==-1){
  400.                 readConnectionTimeout = HttpUtilities.HTTP_READ_CONNECTION_TIMEOUT;
  401.             }
  402.             if(this.debug)
  403.                 this.logger.info("Impostazione http timeout CT["+connectionTimeout+"] RT["+readConnectionTimeout+"]",false);
  404.             requestConfigBuilder.setConnectionRequestTimeout(connectionTimeout);
  405.             requestConfigBuilder.setConnectTimeout(connectionTimeout);
  406.             requestConfigBuilder.setSocketTimeout(readConnectionTimeout);
  407.            


  408.            
  409.            
  410.            
  411.             // Gestione automatica del redirect
  412.             //this.httpConn.setInstanceFollowRedirects(true);
  413.            
  414.            
  415.                
  416.             // Authentication BASIC
  417.             if(this.debug)
  418.                 this.logger.debug("Impostazione autenticazione...");
  419.             String user = null;
  420.             String password = null;
  421.             if(this.credenziali!=null){
  422.                 user = this.credenziali.getUser();
  423.                 password = this.credenziali.getPassword();
  424.             }else{
  425.                 user = this.properties.get(CostantiConnettori.CONNETTORE_USERNAME);
  426.                 password = this.properties.get(CostantiConnettori.CONNETTORE_PASSWORD);
  427.             }
  428.             if(user!=null && password!=null){
  429.                 String authentication = user + ":" + password;
  430.                 authentication = HttpConstants.AUTHORIZATION_PREFIX_BASIC + Base64Utilities.encodeAsString(authentication.getBytes());
  431.                 this.setRequestHeader(HttpConstants.AUTHORIZATION,authentication, propertiesTrasportoDebug);
  432.                 if(this.debug)
  433.                     this.logger.info("Impostazione autenticazione (username:"+user+" password:"+password+") ["+authentication+"]",false);
  434.             }
  435.            
  436.            
  437.            
  438.             // Authentication Token
  439.             NameValue nv = this.getTokenHeader();
  440.             if(nv!=null) {
  441.                 if(this.requestMsg!=null && this.requestMsg.getTransportRequestContext()!=null) {
  442.                     this.requestMsg.getTransportRequestContext().removeHeader(nv.getName()); // Fix: senno sovrascriveva il vecchio token
  443.                 }
  444.                 this.setRequestHeader(nv.getName(),nv.getValue(), propertiesTrasportoDebug);
  445.                 if(this.debug)
  446.                     this.logger.info("Impostazione autenticazione token (header-name '"+nv.getName()+"' value '"+nv.getValue()+"')",false);
  447.             }
  448.            
  449.            
  450.            
  451.            
  452.             // Authentication Api Key
  453.             String apiKey = this.properties.get(CostantiConnettori.CONNETTORE_APIKEY);
  454.             if(apiKey!=null && StringUtils.isNotEmpty(apiKey)){
  455.                 String apiKeyHeader = this.properties.get(CostantiConnettori.CONNETTORE_APIKEY_HEADER);
  456.                 if(apiKeyHeader==null || StringUtils.isEmpty(apiKeyHeader)) {
  457.                     apiKeyHeader = CostantiConnettori.DEFAULT_HEADER_API_KEY;
  458.                 }
  459.                 this.setRequestHeader(apiKeyHeader,apiKey, propertiesTrasportoDebug);
  460.                 if(this.debug)
  461.                     this.logger.info("Impostazione autenticazione api key ["+apiKeyHeader+"]=["+apiKey+"]",false);
  462.                
  463.                 String appId = this.properties.get(CostantiConnettori.CONNETTORE_APIKEY_APPID);
  464.                 if(appId!=null && StringUtils.isNotEmpty(appId)){
  465.                     String appIdHeader = this.properties.get(CostantiConnettori.CONNETTORE_APIKEY_APPID_HEADER);
  466.                     if(appIdHeader==null || StringUtils.isEmpty(appIdHeader)) {
  467.                         appIdHeader = CostantiConnettori.DEFAULT_HEADER_APP_ID;
  468.                     }
  469.                     this.setRequestHeader(appIdHeader,appId, propertiesTrasportoDebug);
  470.                     if(this.debug)
  471.                         this.logger.info("Impostazione autenticazione api key (app id) ["+appIdHeader+"]=["+appId+"]",false);
  472.                 }
  473.             }
  474.            
  475.            
  476.            
  477.            
  478.             // ForwardProxy
  479.             if(this.forwardProxy_headerName!=null && this.forwardProxy_headerValue!=null) {
  480.                 if(this.requestMsg!=null && this.requestMsg.getTransportRequestContext()!=null) {
  481.                     this.requestMsg.getTransportRequestContext().removeHeader(this.forwardProxy_headerName); // Fix: senno sovrascriveva il vecchio token
  482.                 }
  483.                 setRequestHeader(this.forwardProxy_headerName,this.forwardProxy_headerValue, propertiesTrasportoDebug);
  484.                 if(this.debug)
  485.                     this.logger.info("Impostazione ForwardProxy (header-name '"+this.forwardProxy_headerName+"' value '"+this.forwardProxy_headerValue+"')",false);
  486.             }

  487.            
  488.            
  489.             // Impostazione Proprieta del trasporto
  490.             if(this.debug)
  491.                 this.logger.debug("Impostazione header di trasporto...");
  492.             this.forwardHttpRequestHeader();
  493.             if(this.propertiesTrasporto != null){
  494.                 Iterator<String> keys = this.propertiesTrasporto.keySet().iterator();
  495.                 while (keys.hasNext()) {
  496.                     String key = (String) keys.next();
  497.                     List<String> values = this.propertiesTrasporto.get(key);
  498.                     if(this.debug) {
  499.                         if(values!=null && !values.isEmpty()) {
  500.                             for (String value : values) {
  501.                                 this.logger.info("Set Transport Header ["+key+"]=["+value+"]",false);
  502.                             }
  503.                         }
  504.                     }
  505.                    
  506.                     if(this.encodingRFC2047){
  507.                         List<String> valuesEncoded = new ArrayList<>();
  508.                         if(values!=null && !values.isEmpty()) {
  509.                             for (String value : values) {
  510.                                 if(RFC2047Utilities.isAllCharactersInCharset(value, this.charsetRFC2047)==false){
  511.                                     String encoded = RFC2047Utilities.encode(new String(value), this.charsetRFC2047, this.encodingAlgorithmRFC2047);
  512.                                     //System.out.println("@@@@ CODIFICA ["+value+"] in ["+encoded+"]");
  513.                                     if(this.debug)
  514.                                         this.logger.info("RFC2047 Encoded value in ["+encoded+"] (charset:"+this.charsetRFC2047+" encoding-algorithm:"+this.encodingAlgorithmRFC2047+")",false);
  515.                                     valuesEncoded.add(encoded);
  516.                                 }
  517.                                 else{
  518.                                     valuesEncoded.add(value);
  519.                                 }
  520.                             }
  521.                         }
  522.                         setRequestHeader(this.validazioneHeaderRFC2047, key, valuesEncoded, this.logger, propertiesTrasportoDebug);
  523.                     }
  524.                     else{
  525.                         this.setRequestHeader(this.validazioneHeaderRFC2047, key, values, this.logger, propertiesTrasportoDebug);
  526.                     }
  527.                 }
  528.             }
  529.            
  530.            
  531.            
  532.            
  533.             // Aggiunga del SoapAction Header in caso di richiesta SOAP
  534.             // spostato sotto il forwardHeader per consentire alle trasformazioni di modificarla
  535.             if(this.isSoap && this.sbustamentoSoap == false){
  536.                 if(this.debug)
  537.                     this.logger.debug("Impostazione soap action...");
  538.                 boolean existsTransportProperties = false;
  539.                 if(TransportUtils.containsKey(this.propertiesTrasporto, Costanti.SOAP11_MANDATORY_HEADER_HTTP_SOAP_ACTION)){
  540.                     this.soapAction = TransportUtils.getFirstValue(this.propertiesTrasporto, Costanti.SOAP11_MANDATORY_HEADER_HTTP_SOAP_ACTION);
  541.                     existsTransportProperties = (this.soapAction!=null);
  542.                 }
  543.                 if(!existsTransportProperties) {
  544.                     this.soapAction = soapMessageRequest.getSoapAction();
  545.                 }
  546.                 if(this.soapAction==null){
  547.                     this.soapAction="\"OpenSPCoop\"";
  548.                 }
  549.                 if(MessageType.SOAP_11.equals(this.requestMsg.getMessageType()) && !existsTransportProperties){
  550.                     // NOTA non quotare la soap action, per mantenere la trasparenza della PdD
  551.                     this.setRequestHeader(Costanti.SOAP11_MANDATORY_HEADER_HTTP_SOAP_ACTION,this.soapAction, propertiesTrasportoDebug);
  552.                 }
  553.                 if(this.debug)
  554.                     this.logger.info("SOAP Action inviata ["+this.soapAction+"]",false);
  555.             }
  556.            
  557.            
  558.            
  559.            
  560.             // Impostazione Metodo
  561.             HttpBodyParameters httpBody = new  HttpBodyParameters(this.httpMethod, contentTypeRichiesta);
  562.            
  563.            
  564.            
  565.             // Preparazione messaggio da spedire
  566.             // Spedizione byte
  567.             if(httpBody.isDoOutput()){
  568.                 if(this.debug)
  569.                     this.logger.debug("Spedizione byte...");
  570.                 boolean hasContentRestBuilded = false;
  571.                 boolean hasContentRest = false;
  572.                 OpenSPCoop2RestMessage<?> restMessage = null;
  573.                 if(this.isRest) {
  574.                     restMessage = this.requestMsg.castAsRest();
  575.                     hasContentRest = restMessage.hasContent();
  576.                     hasContentRestBuilded = restMessage.isContentBuilded();
  577.                 }
  578.                 if(this.isDumpBinarioRichiesta() || this.isSoap || hasContentRestBuilded) {
  579.                     DumpByteArrayOutputStream bout = new DumpByteArrayOutputStream(this.dumpBinario_soglia, this.dumpBinario_repositoryFile, this.idTransazione,
  580.                             TipoMessaggio.RICHIESTA_USCITA_DUMP_BINARIO.getValue());
  581.                     try {
  582.                         this.emitDiagnosticStartDumpBinarioRichiestaUscita();
  583.                        
  584.                         if(this.isSoap && this.sbustamentoSoap){
  585.                             if(this.debug)
  586.                                 this.logger.debug("Sbustamento...");
  587.                             TunnelSoapUtils.sbustamentoMessaggio(soapMessageRequest,bout);
  588.                         }else{
  589.                             this.requestMsg.writeTo(bout, true);
  590.                         }
  591.                         bout.flush();
  592.                         bout.close();
  593.                         if(this.isDumpBinarioRichiesta()) {
  594.                             this.dumpBinarioRichiestaUscita(bout, requestMessageType, contentTypeRichiesta, this.location, propertiesTrasportoDebug);
  595.                         }
  596.                        
  597.                         HttpEntity httpEntity = null;
  598.                         if(bout.isSerializedOnFileSystem()) {
  599.                             httpEntity = new FileEntity(bout.getSerializedFile());
  600.                         }
  601.                         else {
  602.                             httpEntity = new ByteArrayEntity(bout.toByteArray());
  603.                         }
  604.                         if(this.httpRequest instanceof HttpEntityEnclosingRequestBase){
  605.                             ((HttpEntityEnclosingRequestBase)this.httpRequest).setEntity(httpEntity);
  606.                         }
  607.                         else{
  608.                             throw new Exception("Tipo ["+this.httpRequest.getClass().getName()+"] non utilizzabile per una richiesta di tipo ["+this.httpMethod+"]");
  609.                         }
  610.                     }finally {
  611.                         try {
  612.                             bout.clearResources();
  613.                         }catch(Throwable t) {
  614.                             this.logger.error("Release resources failed: "+t.getMessage(),t);
  615.                         }
  616.                     }
  617.                 }
  618.                 else {
  619.                     // Siamo per forza rest con contenuto non costruito
  620.                     if(hasContentRest) {
  621.                         InputStream isRequest = this.requestMsg.castAsRest().getInputStream();
  622.                         HttpEntity httpEntity = new InputStreamEntity(isRequest);
  623.                         if(this.httpRequest instanceof HttpEntityEnclosingRequestBase){
  624.                             ((HttpEntityEnclosingRequestBase)this.httpRequest).setEntity(httpEntity);
  625.                         }
  626.                         else{
  627.                             throw new Exception("Tipo ["+this.httpRequest.getClass().getName()+"] non utilizzabile per una richiesta di tipo ["+this.httpMethod+"]");
  628.                         }
  629.                     }
  630.                 }
  631.             }
  632.             else {
  633.                 if(this.isDumpBinarioRichiesta()) {
  634.                     // devo registrare almeno gli header HTTP
  635.                     this.emitDiagnosticStartDumpBinarioRichiestaUscita();
  636.                     this.dumpBinarioRichiestaUscita(null, null, null, this.location, propertiesTrasportoDebug);
  637.                 }
  638.             }
  639.            
  640.            
  641.             // Imposto Configurazione
  642.             this.httpRequest.setConfig(requestConfigBuilder.build());
  643.            
  644.            
  645.            
  646.             // Spedizione byte
  647.             if(this.debug)
  648.                 this.logger.debug("Spedizione byte...");
  649.             // Eseguo la richiesta e prendo la risposta
  650.             HttpResponse httpResponse = this.httpClient.execute(this.httpRequest);
  651.            
  652.             this.dataRichiestaInoltrata = DateManager.getDate();
  653.            
  654.             this.httpEntityResponse = httpResponse.getEntity();
  655.            
  656.            
  657.            
  658.             if(this.debug)
  659.                 this.logger.debug("Analisi risposta...");
  660.             Header [] hdrRisposta = httpResponse.getAllHeaders();
  661.             Map<String, List<String>> mapHeaderHttpResponse = new HashMap<>();
  662.             if(hdrRisposta!=null){
  663.                 for (int i = 0; i < hdrRisposta.length; i++) {
  664.                    
  665.                     String key = null;
  666.                     String value = null;
  667.                    
  668.                     if(hdrRisposta[i].getName()==null){
  669.                         // Check per evitare la coppia che ha come chiave null e come valore HTTP OK 200
  670.                         if(this.debug)
  671.                             this.logger.debug("HTTP risposta ["+HttpConstants.RETURN_CODE+"] ["+hdrRisposta[i].getValue()+"]...");
  672.                         key = HttpConstants.RETURN_CODE;
  673.                         value = hdrRisposta[i].getValue();
  674.                     }
  675.                     else{
  676.                         if(this.debug)
  677.                             this.logger.debug("HTTP risposta ["+hdrRisposta[i].getName()+"] ["+hdrRisposta[i].getValue()+"]...");
  678.                         key = hdrRisposta[i].getName();
  679.                         value = hdrRisposta[i].getValue();
  680.                     }
  681.                    
  682.                     TransportUtils.addHeader(this.propertiesTrasportoRisposta, key, value);
  683.                    
  684.                     List<String> list = null;
  685.                     if(mapHeaderHttpResponse.containsKey(key)) {
  686.                         list = mapHeaderHttpResponse.get(key);
  687.                     }
  688.                     if(list==null) {
  689.                         list = new ArrayList<>();
  690.                         mapHeaderHttpResponse.put(key, list);
  691.                     }
  692.                     list.add(value);
  693.                 }
  694.             }
  695.            
  696.             this.tipoRisposta = TransportUtils.getObjectAsString(mapHeaderHttpResponse, HttpConstants.CONTENT_TYPE);
  697.            
  698.             String contentLengthHdr = TransportUtils.getObjectAsString(mapHeaderHttpResponse, HttpConstants.CONTENT_LENGTH);
  699.             if(contentLengthHdr!=null){
  700.                 this.contentLength = Long.parseLong(contentLengthHdr);
  701.             }
  702.             else {
  703.                 if(this.httpEntityResponse.getContentLength()>0){
  704.                     this.contentLength = this.httpEntityResponse.getContentLength();
  705.                 }
  706.             }
  707.            
  708.            
  709.             //System.out.println("TIPO RISPOSTA["+tipoRisposta+"] LOCATION["+locationRisposta+"]");
  710.            
  711.             // Parametri di imbustamento
  712.             if(this.isSoap){
  713.                 if("true".equals(TransportUtils.getObjectAsString(mapHeaderHttpResponse, this.openspcoopProperties.getTunnelSOAPKeyWord_headerTrasporto()))){
  714.                     this.imbustamentoConAttachment = true;
  715.                 }
  716.                 this.mimeTypeAttachment = TransportUtils.getObjectAsString(mapHeaderHttpResponse, this.openspcoopProperties.getTunnelSOAPKeyWordMimeType_headerTrasporto());
  717.                 if(this.mimeTypeAttachment==null)
  718.                     this.mimeTypeAttachment = HttpConstants.CONTENT_TYPE_OPENSPCOOP2_TUNNEL_SOAP;
  719.                 //System.out.println("IMB["+imbustamentoConAttachment+"] MIME["+mimeTypeAttachment+"]");
  720.             }

  721.             // Ricezione Risposta
  722.             if(this.debug)
  723.                 this.logger.debug("Analisi risposta input stream e risultato http...");
  724.             this.initConfigurationAcceptOnlyReturnCode_202_200();
  725.            
  726.             this.codice = httpResponse.getStatusLine().getStatusCode();
  727.             this.resultHTTPMessage = httpResponse.getStatusLine().getReasonPhrase();
  728.            
  729.             if(this.codice<300) {
  730.                 if(this.isSoap && this.acceptOnlyReturnCode_202_200){
  731.                     if(this.codice!=200 && this.codice!=202){
  732.                         throw new Exception("Return code ["+this.codice+"] non consentito dal WS-I Basic Profile (http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html#HTTP_Success_Status_Codes)");
  733.                     }
  734.                 }
  735.                 if(httpBody.isDoInput()){
  736.                     this.isResponse = this.httpEntityResponse.getContent();
  737.                 }
  738.             }else{
  739.                 this.isResponse = this.httpEntityResponse.getContent();
  740.             }
  741.            
  742.            
  743.            
  744.                        
  745.            
  746.            
  747.            
  748.             /* ------------  PostOutRequestHandler ------------- */
  749.             this.postOutRequest();
  750.            
  751.            
  752.            
  753.            
  754.             /* ------------  PreInResponseHandler ------------- */
  755.             this.preInResponse();
  756.            
  757.             // Lettura risposta parametri NotifierInputStream per la risposta
  758.             this.notifierInputStreamParams = null;
  759.             if(this.preInResponseContext!=null){
  760.                 this.notifierInputStreamParams = this.preInResponseContext.getNotifierInputStreamParams();
  761.             }
  762.            
  763.            
  764.            
  765.             /* ------------  Gestione Risposta ------------- */
  766.            
  767.             this.normalizeInputStreamResponse(readConnectionTimeout, readConnectionTimeoutConfigurazioneGlobale);
  768.            
  769.             this.initCheckContentTypeConfiguration();
  770.            
  771.             if(this.isDumpBinarioRisposta()){
  772.                 if(!this.dumpResponse(this.propertiesTrasportoRisposta)) {
  773.                     return false;
  774.                 }
  775.             }
  776.                    
  777.             if(this.isRest){
  778.                
  779.                 if(this.doRestResponse()==false){
  780.                     return false;
  781.                 }
  782.                
  783.             }
  784.             else{
  785.            
  786.                 if(this.doSoapResponse()==false){
  787.                     return false;
  788.                 }
  789.                
  790.             }
  791.            
  792.             if(this.debug)
  793.                 this.logger.info("Gestione invio/risposta http effettuata con successo",false);
  794.            
  795.             return true;            
  796.                        
  797.         }  catch(Exception e){
  798.             this.eccezioneProcessamento = e;
  799.             String msgErrore = this.readExceptionMessageFromException(e);
  800.             if(this.generateErrorWithConnectorPrefix) {
  801.                 this.errore = "Errore avvenuto durante la consegna HTTP: "+msgErrore;
  802.             }
  803.             else {
  804.                 this.errore = msgErrore;
  805.             }
  806.             this.logger.error("Errore avvenuto durante la consegna HTTP: "+msgErrore,e);
  807.            
  808.             this.processConnectionTimeoutException(connectionTimeout, connectionTimeoutConfigurazioneGlobale, e, msgErrore);
  809.            
  810.             this.processReadTimeoutException(readConnectionTimeout, readConnectionTimeoutConfigurazioneGlobale, e, msgErrore);
  811.            
  812.             return false;
  813.         }

  814.     }

  815.    
  816.     @Override
  817.     public void disconnect() throws ConnettoreException{
  818.         List<Throwable> listExceptionChiusura = new ArrayList<Throwable>();
  819.         try{
  820.             // Gestione finale della connessione            
  821.             //System.out.println("CHECK CLOSE STREAM...");
  822.             if(this.isResponse!=null){
  823.                 if(this.debug && this.logger!=null)
  824.                     this.logger.debug("Chiusura socket...");
  825.                 //System.out.println("CLOSE STREAM...");
  826.                 this.isResponse.close();
  827.                 //System.out.println("CLOSE STREAM");
  828.             }              
  829.         }
  830.         catch(Throwable t) {
  831.             if(this.logger!=null) {
  832.                 this.logger.debug("Chiusura socket fallita: "+t.getMessage(),t);
  833.             }
  834.             listExceptionChiusura.add(t);
  835.         }
  836.         try{
  837.             // Gestione finale della connessione
  838.             //System.out.println("CHECK ENTITY...");
  839.             if(this.httpEntityResponse!=null){
  840.                 if(this.debug && this.logger!=null)
  841.                     this.logger.debug("Chiusura httpEntityResponse...");
  842.                 //System.out.println("CLOSE ENTITY...");
  843.                 EntityUtils.consume(this.httpEntityResponse);
  844.                 //System.out.println("CLOSE ENTITY");
  845.             }
  846.            
  847.             if(this.httpEntityResponse!=null){
  848.                
  849.             }
  850.                
  851.         }catch(Throwable t) {
  852.             if(this.logger!=null) {
  853.                 this.logger.debug("Chiusura connessione fallita: "+t.getMessage(),t);
  854.             }
  855.             listExceptionChiusura.add(t);
  856.         }
  857.         try{
  858.             // super.disconnect (Per risorse base)
  859.             super.disconnect();
  860.         }catch(Throwable t) {
  861.             if(this.logger!=null) {
  862.                 this.logger.debug("Chiusura risorse fallita: "+t.getMessage(),t);
  863.             }
  864.             listExceptionChiusura.add(t);
  865.         }
  866.        
  867.         if(listExceptionChiusura!=null && !listExceptionChiusura.isEmpty()) {
  868.             org.openspcoop2.utils.UtilsMultiException multiException = new org.openspcoop2.utils.UtilsMultiException(listExceptionChiusura.toArray(new Throwable[1]));
  869.             throw new ConnettoreException("Chiusura connessione non riuscita: "+multiException.getMessage(),multiException);
  870.         }
  871.     }
  872.        
  873.    
  874.    
  875.     /**
  876.      * Ritorna l'informazione su dove il connettore sta spedendo il messaggio
  877.      *
  878.      * @return location di inoltro del messaggio
  879.      */
  880.     @Override
  881.     public String getLocation(){
  882.         if(this.location==null){
  883.             // può darsi che per un errore non sia ancora stata inizializzata la location
  884.             try{
  885.                 this.buildLocation();
  886.             }catch(Throwable t){}
  887.         }
  888.         if(this.location!=null){
  889.             String l = new String(this.location);
  890. //          if(this.forwardProxy!=null && this.forwardProxy.isEnabled()) {
  891. //              l = l+" [govway-proxy]";
  892. //          }
  893.             return l;
  894.         }
  895.         return null;
  896.     }
  897.     private void buildLocation() throws ConnettoreException {
  898.         this.location = TransportUtils.getObjectAsString(this.properties,CostantiConnettori.CONNETTORE_LOCATION);  
  899.         NameValue nv = this.getTokenQueryParameter();
  900.         if(nv!=null) {
  901.             if(this.requestMsg!=null && this.requestMsg.getTransportRequestContext()!=null) {
  902.                 this.requestMsg.getTransportRequestContext().removeParameter(nv.getName()); // Fix: senno sovrascriveva il vecchio token
  903.             }
  904.             if(this.propertiesUrlBased==null) {
  905.                 this.propertiesUrlBased = new HashMap<>();
  906.             }
  907.             TransportUtils.setParameter(this.propertiesUrlBased, nv.getName(), nv.getValue());
  908.         }
  909.         this.location = ConnettoreUtils.buildLocationWithURLBasedParameter(this.logger!=null ? this.logger.getLogger() : null, this.requestMsg,
  910.                 ConnettoreHTTPCORE.ENDPOINT_TYPE,
  911.                 this.propertiesUrlBased, this.location,
  912.                 this.getProtocolFactory(), this.idModulo);
  913.        
  914.         this.updateLocation_forwardProxy(this.location);
  915.     }
  916.    
  917.    
  918.    
  919.     private void setRequestHeader(boolean validazioneHeaderRFC2047, String key, List<String> values, ConnettoreLogger logger, Map<String, List<String>> propertiesTrasportoDebug) throws Exception {
  920.         if(validazioneHeaderRFC2047){
  921.             try{
  922.                 RFC2047Utilities.validHeader(key, values);
  923.                 setRequestHeader(key, values, propertiesTrasportoDebug);
  924.             }catch(UtilsException e){
  925.                 logger.error(e.getMessage(),e);
  926.             }
  927.         }
  928.         else{
  929.             setRequestHeader(key, values, propertiesTrasportoDebug);
  930.         }
  931.        
  932.     }
  933.    
  934.     @Override
  935.     protected void setRequestHeader(String key, List<String> values) throws Exception {
  936.         if(values!=null && !values.isEmpty()) {
  937.             for (String value : values) {
  938.                 this.httpRequest.addHeader(key,value);      
  939.             }
  940.         }
  941.     }
  942. }

  943. class ConnectionKeepAliveStrategyCustom implements ConnectionKeepAliveStrategy{

  944.     @Override
  945.     public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
  946.        
  947.          // Honor 'keep-alive' header
  948.         HeaderElementIterator it = new BasicHeaderElementIterator(
  949.                 response.headerIterator(HTTP.CONN_KEEP_ALIVE));
  950.         while (it.hasNext()) {
  951.             HeaderElement he = it.nextElement();
  952.             String param = he.getName();
  953.             String value = he.getValue();
  954.             if (value != null && param.equalsIgnoreCase("timeout")) {
  955.                 try {
  956.                     //System.out.println("RETURN HEADER ["+ (Long.parseLong(value) * 1000)+"]");
  957.                     return Long.parseLong(value) * 1000;
  958.                 } catch(NumberFormatException ignore) {
  959.                 }
  960.             }
  961.         }
  962. //        HttpHost target = (HttpHost) context.getAttribute(
  963. //                ExecutionContext.HTTP_TARGET_HOST);
  964. //        if ("www.naughty-server.com".equalsIgnoreCase(target.getHostName())) {
  965. //            // Keep alive for 5 seconds only
  966. //            return 5 * 1000;
  967. //        } else {
  968. //            // otherwise keep alive for 30 seconds
  969. //            return 30 * 1000;
  970. //        }
  971.         // otherwise keep alive for 2 minutes
  972.         //System.out.println("RETURN 2 minuti");
  973.         return 2l * 60l * 1000l;
  974.        
  975.     }
  976.    
  977. }

  978. class CustomHttpEntity extends HttpEntityEnclosingRequestBase{

  979.     private HttpRequestMethod httpMethod;
  980.     public CustomHttpEntity(HttpRequestMethod httpMethod) {
  981.         super();
  982.         this.httpMethod = httpMethod;
  983.     }
  984.    
  985.     public CustomHttpEntity(HttpRequestMethod httpMethod, final URI uri) {
  986.         super();
  987.         setURI(uri);
  988.         this.httpMethod = httpMethod;
  989.     }

  990.     public CustomHttpEntity(HttpRequestMethod httpMethod, final String uri) {
  991.         super();
  992.         setURI(URI.create(uri));
  993.         this.httpMethod = httpMethod;
  994.     }
  995.    
  996.     @Override
  997.     public String getMethod() {
  998.         return this.httpMethod.name();
  999.     }
  1000.    
  1001. }