Java tutorial
//$Header: /cvsroot-fuse/mec-as2/39/mendelson/comm/as2/send/MessageHttpUploader.java,v 1.1 2012/04/18 14:10:35 heller Exp $ package de.mendelson.comm.as2.send; import de.mendelson.comm.as2.client.rmi.GenericClient; import de.mendelson.comm.as2.clientserver.ErrorObject; import de.mendelson.comm.as2.clientserver.message.RefreshClientMessageOverviewList; import de.mendelson.comm.as2.clientserver.serialize.CommandObjectIncomingMessage; import de.mendelson.comm.as2.message.AS2Info; import de.mendelson.comm.as2.message.AS2MDNInfo; import de.mendelson.comm.as2.message.AS2Message; import de.mendelson.comm.as2.message.AS2MessageInfo; import de.mendelson.comm.as2.message.MDNAccessDB; import de.mendelson.comm.as2.message.MessageAccessDB; import de.mendelson.comm.as2.message.store.MessageStoreHandler; import de.mendelson.comm.as2.partner.HTTPAuthentication; import de.mendelson.comm.as2.partner.Partner; import de.mendelson.comm.as2.partner.PartnerHttpHeader; import de.mendelson.comm.as2.preferences.PreferencesAS2; import de.mendelson.comm.as2.server.AS2Server; import de.mendelson.comm.as2.statistic.QuotaAccessDB; import de.mendelson.util.AS2Tools; import de.mendelson.util.MecResourceBundle; import de.mendelson.util.clientserver.ClientServer; import de.mendelson.util.security.BCCryptoHelper; import de.mendelson.util.security.cert.KeystoreStorage; import de.mendelson.util.security.cert.KeystoreStorageImplFile; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLDecoder; import java.sql.Connection; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.http.HttpServletResponse; import org.apache.http.Header; import org.apache.http.HttpException; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.StatusLine; import org.apache.http.auth.AuthScheme; import org.apache.http.auth.AuthScope; import org.apache.http.auth.AuthState; import org.apache.http.auth.Credentials; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.protocol.ClientContext; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.conn.params.ConnRouteParams; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.NoConnectionReuseStrategy; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; /* * Copyright (C) mendelson-e-commerce GmbH Berlin Germany * * This software is subject to the license agreement set forth in the license. * Please read and agree to all terms before using this software. * Other product and brand names are trademarks of their respective owners. */ /** * Class to allow HTTP multipart uploads * @author S.Heller * @version $Revision: 1.1 $ */ public class MessageHttpUploader { private Logger logger = null; private PreferencesAS2 preferences = new PreferencesAS2(); /**localisze the GUI*/ private MecResourceBundle rb = null; /**The header that has been built fro the request*/ private Properties requestHeader = new Properties(); /**remote answer*/ private byte[] responseData = null; /**remote answer*/ private Header[] responseHeader = null; /**remote answer*/ private StatusLine responseStatusLine = null; private ClientServer clientserver = null; //DB connection private Connection configConnection = null; private Connection runtimeConnection = null; //keystore data private KeystoreStorage certStore = null; private KeystoreStorage trustStore = null; /** Creates new message uploader instance * @param hostname Name of the host to connect to * @param username Name of the user that will connect to the remote ftp server * @param password password to connect to the ftp server */ public MessageHttpUploader() throws Exception { //Load default resourcebundle try { this.rb = (MecResourceBundle) ResourceBundle.getBundle(ResourceBundleHttpUploader.class.getName()); } //load up resourcebundle catch (MissingResourceException e) { throw new RuntimeException("Oops..resource bundle " + e.getClassName() + " not found."); } } /**Sets keystore parameter for SSL sending. This is only necessary if HTTPS is the * protocol used for the message POST * @param truststore Truststore file * @param truststorePass Password for the truststore * @param certstore Keystore file * @param certstorePass Password for the keystore */ public void setSSLParameter(KeystoreStorage certStore, KeystoreStorage trustStore) { this.certStore = certStore; this.trustStore = trustStore; } /**Passes a logger to this class for logging purpose*/ public void setLogger(Logger logger) { this.logger = logger; } /**Passes a server instance to this class to refresh messages automatically for logging purpose*/ public void setAbstractServer(ClientServer clientserver) { this.clientserver = clientserver; } /**Pass a DB connection to this class for loggin purpose*/ public void setDBConnection(Connection configConnection, Connection runtimeConnection) { this.configConnection = configConnection; this.runtimeConnection = runtimeConnection; } /**Returns the created header for the sent data*/ public Properties upload(HttpConnectionParameter connectionParameter, AS2Message message, Partner sender, Partner receiver) throws Exception { NumberFormat formatter = new DecimalFormat("0.00"); AS2Info as2Info = message.getAS2Info(); MessageAccessDB messageAccess = null; MDNAccessDB mdnAccess = null; if (this.runtimeConnection != null && messageAccess == null && !as2Info.isMDN()) { messageAccess = new MessageAccessDB(this.configConnection, this.runtimeConnection); messageAccess.initializeOrUpdateMessage((AS2MessageInfo) as2Info); } else if (this.runtimeConnection != null && as2Info.isMDN()) { mdnAccess = new MDNAccessDB(this.configConnection, this.runtimeConnection); mdnAccess.initializeOrUpdateMDN((AS2MDNInfo) as2Info); } if (this.clientserver != null) { this.clientserver.broadcastToClients(new RefreshClientMessageOverviewList()); } long startTime = System.currentTimeMillis(); //sets the global requestHeader int returnCode = this.performUpload(connectionParameter, message, sender, receiver); long size = message.getRawDataSize(); long transferTime = System.currentTimeMillis() - startTime; float bytePerSec = (float) ((float) size * 1000f / (float) transferTime); float kbPerSec = (float) (bytePerSec / 1024f); if (returnCode == HttpServletResponse.SC_OK) { if (this.logger != null) { this.logger.log(Level.INFO, this.rb.getResourceString("returncode.ok", new Object[] { as2Info.getMessageId(), String.valueOf(returnCode), AS2Tools.getDataSizeDisplay(size), AS2Tools.getTimeDisplay(transferTime), formatter.format(kbPerSec), }), as2Info); } } else if (returnCode == HttpServletResponse.SC_ACCEPTED || returnCode == HttpServletResponse.SC_CREATED || returnCode == HttpServletResponse.SC_NO_CONTENT || returnCode == HttpServletResponse.SC_RESET_CONTENT || returnCode == HttpServletResponse.SC_PARTIAL_CONTENT) { if (this.logger != null) { this.logger.log(Level.INFO, this.rb.getResourceString("returncode.accepted", new Object[] { as2Info.getMessageId(), String.valueOf(returnCode), AS2Tools.getDataSizeDisplay(size), AS2Tools.getTimeDisplay(transferTime), formatter.format(kbPerSec), }), as2Info); } } else { //the system was unable to connect the partner if (returnCode < 0) { throw new NoConnectionException( this.rb.getResourceString("error.noconnection", as2Info.getMessageId())); } if (this.runtimeConnection != null) { if (messageAccess == null) { messageAccess = new MessageAccessDB(this.configConnection, this.runtimeConnection); } messageAccess.setMessageState(as2Info.getMessageId(), AS2Message.STATE_STOPPED); } throw new Exception(as2Info.getMessageId() + ": HTTP " + returnCode); } if (this.configConnection != null) { //inc the sent data size, this is for new connections (as2 messages, async mdn) AS2Server.incRawSentData(size); if (message.getAS2Info().isMDN()) { AS2MDNInfo mdnInfo = (AS2MDNInfo) message.getAS2Info(); //ASYNC MDN sent: insert an entry into the statistic table QuotaAccessDB.incReceivedMessages(this.configConnection, this.runtimeConnection, mdnInfo.getSenderId(), mdnInfo.getReceiverId(), mdnInfo.getState(), mdnInfo.getRelatedMessageId()); } } if (this.configConnection != null) { MessageStoreHandler messageStoreHandler = new MessageStoreHandler(this.configConnection, this.runtimeConnection); messageStoreHandler.storeSentMessage(message, sender, receiver, this.requestHeader); } //inform the server of the result if a sync MDN has been requested if (!message.isMDN()) { AS2MessageInfo messageInfo = (AS2MessageInfo) message.getAS2Info(); if (messageInfo.requestsSyncMDN()) { //perform a check if the answer really contains a MDN or is just an empty HTTP 200 with some header data //this check looks for the existance of some key header values boolean as2FromExists = false; boolean as2ToExists = false; for (int i = 0; i < this.getResponseHeader().length; i++) { String key = this.getResponseHeader()[i].getName(); if (key.toLowerCase().equals("as2-to")) { as2ToExists = true; } else if (key.toLowerCase().equals("as2-from")) { as2FromExists = true; } } if (!as2ToExists) { throw new Exception(this.rb.getResourceString("answer.no.sync.mdn", new Object[] { as2Info.getMessageId(), "as2-to" })); } //send the data to the as2 server. It does not care if the MDN has been sync or async anymore GenericClient client = new GenericClient(); CommandObjectIncomingMessage commandObject = new CommandObjectIncomingMessage(); //create temporary file to store the data File tempFile = AS2Tools.createTempFile("SYNCMDN_received", ".bin"); FileOutputStream outStream = new FileOutputStream(tempFile); ByteArrayInputStream memIn = new ByteArrayInputStream(this.responseData); this.copyStreams(memIn, outStream); memIn.close(); outStream.flush(); outStream.close(); commandObject.setMessageDataFilename(tempFile.getAbsolutePath()); for (int i = 0; i < this.getResponseHeader().length; i++) { String key = this.getResponseHeader()[i].getName(); String value = this.getResponseHeader()[i].getValue(); commandObject.addHeader(key.toLowerCase(), value); if (key.toLowerCase().equals("content-type")) { commandObject.setContentType(value); } } //compatibility issue: some AS2 systems do not send a as2-from in the sync case, even if //this if _NOT_ RFC conform //see RFC 4130, section 6.2: The AS2-To and AS2-From header fields MUST be //present in all AS2 messages and AS2 MDNs whether asynchronous or synchronous in nature, //except for asynchronous MDNs, which are sent using SMTP. if (!as2FromExists) { commandObject.addHeader("as2-from", AS2Message.escapeFromToHeader(receiver.getAS2Identification())); } ErrorObject errorObject = client.send(commandObject); if (errorObject.getErrors() > 0) { messageAccess.setMessageState(as2Info.getMessageId(), AS2Message.STATE_STOPPED); } tempFile.delete(); } } return (this.requestHeader); } /**Sets necessary HTTP authentication for this partner, depending on if it is an asny MDN that will be sent or an AS2 message. *If the partner is not configured to use HTTP authentication in any kind nothing will happen in here */ private void setHTTPAuthentication(DefaultHttpClient client, Partner receiver, boolean isMDN) { HTTPAuthentication authentication = null; if (isMDN) { authentication = receiver.getAuthenticationAsyncMDN(); } else { authentication = receiver.getAuthentication(); } if (authentication.isEnabled()) { Credentials userPassCredentials = new UsernamePasswordCredentials(authentication.getUser(), authentication.getPassword()); client.getCredentialsProvider().setCredentials(AuthScope.ANY, userPassCredentials); BasicHttpContext localcontext = new BasicHttpContext(); // Generate BASIC scheme object and stick it to the local // execution context BasicScheme basicAuth = new BasicScheme(); localcontext.setAttribute("preemptive-auth", basicAuth); // Add as the first request interceptor client.addRequestInterceptor(new PreemptiveAuth(), 0); } } /**Builds a proxy object from the actual preferences, returns null if no proxy is requested*/ public ProxyObject createProxyObjectFromPreferences() { if (!this.preferences.getBoolean(PreferencesAS2.PROXY_USE)) { //return empty proxy object, is not used return (null); } ProxyObject proxy = new ProxyObject(); proxy.setHost(this.preferences.get(PreferencesAS2.PROXY_HOST)); proxy.setPort(this.preferences.getInt(PreferencesAS2.PROXY_PORT)); if (this.preferences.getBoolean(PreferencesAS2.AUTH_PROXY_USE)) { proxy.setUser(this.preferences.get(PreferencesAS2.AUTH_PROXY_USER)); proxy.setPassword(this.preferences.get(PreferencesAS2.AUTH_PROXY_PASS).toCharArray()); } return (proxy); } /**Sets the proxy authentification for the client*/ private void setProxyToConnection(DefaultHttpClient client, AS2Message message, ProxyObject proxy) { //is a proxy requested? if (proxy.getHost() == null) { return; } HttpHost proxyHost = new HttpHost(proxy.getHost(), proxy.getPort(), "http"); client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxyHost); if (proxy.getUser() != null) { CredentialsProvider credsProvider = new BasicCredentialsProvider(); credsProvider.setCredentials(new AuthScope(proxy.getHost(), proxy.getPort()), new UsernamePasswordCredentials(proxy.getUser(), String.valueOf(proxy.getPassword()))); client.setCredentialsProvider(credsProvider); } if (this.logger != null) { this.logger.log(Level.INFO, this.rb.getResourceString("using.proxy", new Object[] { message.getAS2Info().getMessageId(), proxy.getHost(), String.valueOf(proxy.getPort()), }), message.getAS2Info()); } } /**Uploads the data, returns the HTTP result code*/ public int performUpload(HttpConnectionParameter connectionParameter, AS2Message message, Partner sender, Partner receiver) { return (this.performUpload(connectionParameter, message, sender, receiver, null)); } /**Uploads the data, returns the HTTP result code*/ public int performUpload(HttpConnectionParameter connectionParameter, AS2Message message, Partner sender, Partner receiver, URL receiptURL) { String ediintFeatures = "multiple-attachments, CEM"; //set the http connection/routing/protocol parameter HttpParams httpParams = new BasicHttpParams(); if (connectionParameter.getConnectionTimeoutMillis() != -1) { HttpConnectionParams.setConnectionTimeout(httpParams, connectionParameter.getConnectionTimeoutMillis()); } if (connectionParameter.getSoTimeoutMillis() != -1) { HttpConnectionParams.setSoTimeout(httpParams, connectionParameter.getSoTimeoutMillis()); } HttpConnectionParams.setStaleCheckingEnabled(httpParams, connectionParameter.isStaleConnectionCheck()); if (connectionParameter.getHttpProtocolVersion() == null) { //default settings: HTTP 1.1 HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); } else if (connectionParameter.getHttpProtocolVersion().equals(HttpConnectionParameter.HTTP_1_0)) { HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_0); } else if (connectionParameter.getHttpProtocolVersion().equals(HttpConnectionParameter.HTTP_1_1)) { HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); } HttpProtocolParams.setUseExpectContinue(httpParams, connectionParameter.isUseExpectContinue()); HttpProtocolParams.setUserAgent(httpParams, connectionParameter.getUserAgent()); if (connectionParameter.getLocalAddress() != null) { ConnRouteParams.setLocalAddress(httpParams, connectionParameter.getLocalAddress()); } int status = -1; HttpPost filePost = null; DefaultHttpClient httpClient = null; try { ClientConnectionManager clientConnectionManager = this.createClientConnectionManager(httpParams); httpClient = new DefaultHttpClient(clientConnectionManager, httpParams); //some ssl implementations have problems with a session/connection reuse httpClient.setReuseStrategy(new NoConnectionReuseStrategy()); //disable SSL hostname verification. Do not confuse this with SSL trust verification! SSLSocketFactory sslFactory = (SSLSocketFactory) httpClient.getConnectionManager().getSchemeRegistry() .get("https").getSocketFactory(); sslFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //determine the receipt URL if it is not set if (receiptURL == null) { //async MDN requested? if (message.isMDN()) { if (this.runtimeConnection == null) { throw new IllegalArgumentException( "MessageHTTPUploader.performUpload(): A MDN receipt URL is not set, unable to determine where to send the MDN"); } MessageAccessDB messageAccess = new MessageAccessDB(this.configConnection, this.runtimeConnection); AS2MessageInfo relatedMessageInfo = messageAccess .getLastMessageEntry(((AS2MDNInfo) message.getAS2Info()).getRelatedMessageId()); receiptURL = new URL(relatedMessageInfo.getAsyncMDNURL()); } else { receiptURL = new URL(receiver.getURL()); } } filePost = new HttpPost(receiptURL.toExternalForm()); filePost.addHeader("as2-version", "1.2"); filePost.addHeader("ediint-features", ediintFeatures); filePost.addHeader("mime-version", "1.0"); filePost.addHeader("recipient-address", receiptURL.toExternalForm()); filePost.addHeader("message-id", "<" + message.getAS2Info().getMessageId() + ">"); filePost.addHeader("as2-from", AS2Message.escapeFromToHeader(sender.getAS2Identification())); filePost.addHeader("as2-to", AS2Message.escapeFromToHeader(receiver.getAS2Identification())); String originalFilename = null; if (message.getPayloads() != null && message.getPayloads().size() > 0) { originalFilename = message.getPayloads().get(0).getOriginalFilename(); } if (originalFilename != null) { String subject = this.replace(message.getAS2Info().getSubject(), "${filename}", originalFilename); filePost.addHeader("subject", subject); //update the message infos subject with the actual content if (!message.isMDN()) { ((AS2MessageInfo) message.getAS2Info()).setSubject(subject); //refresh this in the database if it is requested if (this.runtimeConnection != null) { MessageAccessDB access = new MessageAccessDB(this.configConnection, this.runtimeConnection); access.updateSubject((AS2MessageInfo) message.getAS2Info()); } } } else { filePost.addHeader("subject", message.getAS2Info().getSubject()); } filePost.addHeader("from", sender.getEmail()); filePost.addHeader("connection", "close, TE"); //the data header must be always in english locale else there would be special //french characters (e.g. 13 dc. 2011 16:28:56 CET) which is not allowed after //RFC 4130 DateFormat format = new SimpleDateFormat("EE, dd MMM yyyy HH:mm:ss zz", Locale.US); filePost.addHeader("date", format.format(new Date())); String contentType = null; if (message.getAS2Info().getEncryptionType() != AS2Message.ENCRYPTION_NONE) { contentType = "application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m"; } else { contentType = message.getContentType(); } filePost.addHeader("content-type", contentType); //MDN header, this is always the way for async MDNs if (message.isMDN()) { if (this.logger != null) { this.logger.log(Level.INFO, this.rb.getResourceString("sending.mdn.async", new Object[] { message.getAS2Info().getMessageId(), receiptURL }), message.getAS2Info()); } filePost.addHeader("server", message.getAS2Info().getUserAgent()); } else { AS2MessageInfo messageInfo = (AS2MessageInfo) message.getAS2Info(); //outbound AS2/CEM message if (messageInfo.requestsSyncMDN()) { if (this.logger != null) { if (messageInfo.getMessageType() == AS2Message.MESSAGETYPE_CEM) { this.logger.log(Level.INFO, this.rb.getResourceString("sending.cem.sync", new Object[] { messageInfo.getMessageId(), receiver.getURL() }), messageInfo); } else if (messageInfo.getMessageType() == AS2Message.MESSAGETYPE_AS2) { this.logger.log(Level.INFO, this.rb.getResourceString("sending.msg.sync", new Object[] { messageInfo.getMessageId(), receiver.getURL() }), messageInfo); } } } else { //Message with ASYNC MDN request if (this.logger != null) { if (messageInfo.getMessageType() == AS2Message.MESSAGETYPE_CEM) { this.logger.log(Level.INFO, this.rb.getResourceString("sending.cem.async", new Object[] { messageInfo.getMessageId(), receiver.getURL(), sender.getMdnURL() }), messageInfo); } else if (messageInfo.getMessageType() == AS2Message.MESSAGETYPE_AS2) { this.logger.log(Level.INFO, this.rb.getResourceString("sending.msg.async", new Object[] { messageInfo.getMessageId(), receiver.getURL(), sender.getMdnURL() }), messageInfo); } } //The following header indicates that this requests an asnc MDN. //When the header "receipt-delivery-option" is present, //the header "disposition-notification-to" serves as a request //for an asynchronous MDN. //The header "receipt-delivery-option" must always be accompanied by //the header "disposition-notification-to". //When the header "receipt-delivery-option" is not present and the header //"disposition-notification-to" is present, the header "disposition-notification-to" //serves as a request for a synchronous MDN. filePost.addHeader("receipt-delivery-option", sender.getMdnURL()); } filePost.addHeader("disposition-notification-to", sender.getMdnURL()); //request a signed MDN if this is set up in the partner configuration if (receiver.isSignedMDN()) { filePost.addHeader("disposition-notification-options", messageInfo.getDispositionNotificationOptions().getHeaderValue()); } if (messageInfo.getSignType() != AS2Message.SIGNATURE_NONE) { filePost.addHeader("content-disposition", "attachment; filename=\"smime.p7m\""); } else if (messageInfo.getSignType() == AS2Message.SIGNATURE_NONE && message.getAS2Info().getSignType() == AS2Message.ENCRYPTION_NONE) { filePost.addHeader("content-disposition", "attachment; filename=\"" + message.getPayload(0).getOriginalFilename() + "\""); } } int port = receiptURL.getPort(); if (port == -1) { port = receiptURL.getDefaultPort(); } filePost.addHeader("host", receiptURL.getHost() + ":" + port); InputStream rawDataInputStream = message.getRawDataInputStream(); InputStreamEntity postEntity = new InputStreamEntity(rawDataInputStream, message.getRawDataSize()); postEntity.setContentType(contentType); filePost.setEntity(postEntity); if (connectionParameter.getProxy() != null) { this.setProxyToConnection(httpClient, message, connectionParameter.getProxy()); } this.setHTTPAuthentication(httpClient, receiver, message.getAS2Info().isMDN()); this.updateUploadHttpHeader(filePost, receiver); HttpHost targetHost = new HttpHost(receiptURL.getHost(), receiptURL.getPort(), receiptURL.getProtocol()); BasicHttpContext localcontext = new BasicHttpContext(); // Generate BASIC scheme object and stick it to the local // execution context. Without this a HTTP authentication will not be sent BasicScheme basicAuth = new BasicScheme(); localcontext.setAttribute("preemptive-auth", basicAuth); HttpResponse httpResponse = httpClient.execute(targetHost, filePost, localcontext); rawDataInputStream.close(); this.responseData = this.readEntityData(httpResponse); if (httpResponse != null) { this.responseStatusLine = httpResponse.getStatusLine(); status = this.responseStatusLine.getStatusCode(); this.responseHeader = httpResponse.getAllHeaders(); } for (Header singleHeader : filePost.getAllHeaders()) { if (singleHeader.getValue() != null) { this.requestHeader.setProperty(singleHeader.getName(), singleHeader.getValue()); } } //accept all 2xx answers //SC_ACCEPTED Status code (202) indicating that a request was accepted for processing, but was not completed. //SC_CREATED Status code (201) indicating the request succeeded and created a new resource on the server. //SC_NO_CONTENT Status code (204) indicating that the request succeeded but that there was no new information to return. //SC_NON_AUTHORITATIVE_INFORMATION Status code (203) indicating that the meta information presented by the client did not originate from the server. //SC_OK Status code (200) indicating the request succeeded normally. //SC_RESET_CONTENT Status code (205) indicating that the agent SHOULD reset the document view which caused the request to be sent. //SC_PARTIAL_CONTENT Status code (206) indicating that the server has fulfilled the partial GET request for the resource. if (status != HttpServletResponse.SC_OK && status != HttpServletResponse.SC_ACCEPTED && status != HttpServletResponse.SC_CREATED && status != HttpServletResponse.SC_NO_CONTENT && status != HttpServletResponse.SC_NON_AUTHORITATIVE_INFORMATION && status != HttpServletResponse.SC_RESET_CONTENT && status != HttpServletResponse.SC_PARTIAL_CONTENT) { if (this.logger != null) { this.logger .severe(this.rb.getResourceString("error.httpupload", new Object[] { message.getAS2Info().getMessageId(), URLDecoder.decode( this.responseStatusLine == null ? "" : this.responseStatusLine.getReasonPhrase(), "UTF-8") })); } } } catch (Exception ex) { if (this.logger != null) { StringBuilder errorMessage = new StringBuilder(message.getAS2Info().getMessageId()); errorMessage.append(": MessageHTTPUploader.performUpload: ["); errorMessage.append(ex.getClass().getSimpleName()); errorMessage.append("]"); if (ex.getMessage() != null) { errorMessage.append(": ").append(ex.getMessage()); } this.logger.log(Level.SEVERE, errorMessage.toString(), message.getAS2Info()); } } finally { if (httpClient != null && httpClient.getConnectionManager() != null) { //shutdown the HTTPClient to release the resources httpClient.getConnectionManager().shutdown(); } } return (status); } private ClientConnectionManager createClientConnectionManager(HttpParams httpParams) throws Exception { //register protocols SchemeRegistry registry = new SchemeRegistry(); Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80); registry.register(http); registry.register(this.createHTTPSScheme()); ClientConnectionManager manager = new ThreadSafeClientConnManager(httpParams, registry); return (manager); } private Scheme createHTTPSScheme() throws Exception { //cert store not set so far: take the preferences data if (this.certStore == null) { this.certStore = new KeystoreStorageImplFile(this.preferences.get(PreferencesAS2.KEYSTORE_HTTPS_SEND), this.preferences.get(PreferencesAS2.KEYSTORE_HTTPS_SEND_PASS).toCharArray(), BCCryptoHelper.KEYSTORE_JKS); this.trustStore = new KeystoreStorageImplFile(this.preferences.get(PreferencesAS2.KEYSTORE_HTTPS_SEND), this.preferences.get(PreferencesAS2.KEYSTORE_HTTPS_SEND_PASS).toCharArray(), BCCryptoHelper.KEYSTORE_JKS); } SSLSocketFactory socketFactory = new SSLSocketFactory(this.certStore.getKeystore(), new String(this.certStore.getKeystorePass()), this.trustStore.getKeystore()); socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); return (new Scheme("https", socketFactory, 443)); } /**Updates the passed post HTTP headers with the headers defined for the sender*/ private void updateUploadHttpHeader(HttpPost post, Partner receiver) { List<String> usedHeaderKeys = new ArrayList<String>(); for (Header singleHeader : post.getAllHeaders()) { PartnerHttpHeader headerReplacement = receiver.getHttpHeader(singleHeader.getName()); if (headerReplacement != null) { //a value to replace is set if (headerReplacement.getValue() != null && headerReplacement.getValue().length() > 0) { post.setHeader(singleHeader.getName(), headerReplacement.getValue()); } else { //no value to replace is set: delete the header post.removeHeader(singleHeader); } usedHeaderKeys.add(singleHeader.getName()); } } //add additional user defined headers List<PartnerHttpHeader> additionalHeaders = receiver.getAllNonListedHttpHeader(usedHeaderKeys); for (PartnerHttpHeader additionalHeader : additionalHeaders) { //add the header if a value is set if (additionalHeader.getValue() != null && additionalHeader.getValue().length() > 0) { post.setHeader(additionalHeader.getKey(), additionalHeader.getValue()); } } } /** Replaces the string tag by the string replacement in the sourceString * @param source Source string * @param tag String that will be replaced * @param replacement String that will replace the tag * @return String that contains the replaced values */ private String replace(String source, String tag, String replacement) { if (source == null) { return null; } StringBuilder buffer = new StringBuilder(); while (true) { int index = source.indexOf(tag); if (index == -1) { buffer.append(source); return (buffer.toString()); } buffer.append(source.substring(0, index)); buffer.append(replacement); source = source.substring(index + tag.length()); } } /**Returns the version of this class*/ public static String getVersion() { String revision = "$Revision: 1.1 $"; return (revision.substring(revision.indexOf(":") + 1, revision.lastIndexOf("$")).trim()); } /**Copies all data from one stream to another*/ private void copyStreams(InputStream in, OutputStream out) throws IOException { BufferedInputStream inStream = new BufferedInputStream(in); BufferedOutputStream outStream = new BufferedOutputStream(out); //copy the contents to an output stream byte[] buffer = new byte[1024]; int read = 1024; //a read of 0 must be allowed, sometimes it takes time to //extract data from the input while (read != -1) { read = inStream.read(buffer); if (read > 0) { outStream.write(buffer, 0, read); } } outStream.flush(); } /**Returns the response data as byte array*/ public byte[] getResponseData() { return (this.responseData); } /**Reads the data of a HTTP response entity*/ public byte[] readEntityData(HttpResponse httpResponse) throws Exception { if (httpResponse == null) { return (null); } if (httpResponse.getEntity() == null) { return (null); } ByteArrayOutputStream outStream = new ByteArrayOutputStream(); httpResponse.getEntity().writeTo(outStream); outStream.flush(); outStream.close(); return (outStream.toByteArray()); } /**Returns the array of response headers after the upload process has been performed * @return the responseHeader */ public Header[] getResponseHeader() { if (this.responseHeader == null) { return (new Header[0]); } return (this.responseHeader); } static class PreemptiveAuth implements HttpRequestInterceptor { @Override public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE); // If no auth scheme avaialble yet, try to initialize it preemptively if (authState.getAuthScheme() == null) { AuthScheme authScheme = (AuthScheme) context.getAttribute("preemptive-auth"); CredentialsProvider credsProvider = (CredentialsProvider) context .getAttribute(ClientContext.CREDS_PROVIDER); HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST); if (authScheme != null) { Credentials creds = credsProvider .getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort())); if (creds == null) { throw new HttpException("No credentials for preemptive authentication"); } authState.setAuthScheme(authScheme); authState.setCredentials(creds); } } } } }