/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wsdl.submit.filters; import com.eviware.soapui.SoapUI; import com.eviware.soapui.impl.rest.support.RestParamProperty; import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder; import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder.ParameterStyle; import com.eviware.soapui.impl.rest.support.RestUtils; import com.eviware.soapui.impl.support.HttpUtils; import com.eviware.soapui.impl.support.http.HttpRequestInterface; import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport; import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.AttachmentDataSource; import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.AttachmentUtils; import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.RestRequestDataSource; import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.RestRequestMimeMessageRequestEntity; import com.eviware.soapui.impl.wsdl.support.FileAttachment; import com.eviware.soapui.impl.wsdl.support.PathUtils; import com.eviware.soapui.impl.wsdl.teststeps.HttpTestRequest; import com.eviware.soapui.model.iface.Attachment; import com.eviware.soapui.model.iface.SubmitContext; import com.eviware.soapui.model.propertyexpansion.PropertyExpander; import com.eviware.soapui.settings.HttpSettings; import com.eviware.soapui.support.StringUtils; import com.eviware.soapui.support.editor.inspectors.attachments.ContentTypeHandler; import com.eviware.soapui.support.types.StringToStringMap; import org.apache.commons.httpclient.URI; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.utils.URIUtils; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.StringEntity; import org.apache.xmlbeans.XmlBoolean; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.mail.MessagingException; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.mail.internet.PreencodedMimeBodyPart; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; import static com.eviware.soapui.impl.support.HttpUtils.urlEncodeWithUtf8; /** * RequestFilter that adds SOAP specific headers * * @author Ole.Matzura */ public class HttpRequestFilter extends AbstractRequestFilter { @Override public void filterHttpRequest(SubmitContext context, HttpRequestInterface<?> request) { HttpRequestBase httpMethod = (HttpRequestBase) context.getProperty(BaseHttpRequestTransport.HTTP_METHOD); String path = PropertyExpander.expandProperties(context, request.getPath()); StringBuilder query = new StringBuilder(); String encoding = System.getProperty("soapui.request.encoding", StringUtils.unquote(request.getEncoding())); StringToStringMap responseProperties = (StringToStringMap) context .getProperty(BaseHttpRequestTransport.RESPONSE_PROPERTIES); MimeMultipart formMp = ("multipart/form-data".equals(request.getMediaType()) || "multipart/mixed".equals(request.getMediaType())) && httpMethod instanceof HttpEntityEnclosingRequestBase ? new MimeMultipart() : null; RestParamsPropertyHolder params = request.getParams(); for (int c = 0; c < params.getPropertyCount(); c++) { RestParamProperty param = params.getPropertyAt(c); String value = PropertyExpander.expandProperties(context, param.getValue()); responseProperties.put(param.getName(), value); List<String> valueParts = sendEmptyParameters(request) || (!StringUtils.hasContent(value) && param.getRequired()) ? RestUtils .splitMultipleParametersEmptyIncluded(value, request.getMultiValueDelimiter()) : RestUtils .splitMultipleParameters(value, request.getMultiValueDelimiter()); // skip HEADER and TEMPLATE parameter encoding (TEMPLATE is encoded by // the URI handling further down) if (value != null && param.getStyle() != ParameterStyle.HEADER && param.getStyle() != ParameterStyle.TEMPLATE && !param.isDisableUrlEncoding()) { try { if (StringUtils.hasContent(encoding)) { value = URLEncoder.encode(value, encoding); for (int i = 0; i < valueParts.size(); i++) { valueParts.set(i, URLEncoder.encode(valueParts.get(i), encoding)); } } else { value = urlEncodeWithUtf8(value); for (int i = 0; i < valueParts.size(); i++) { valueParts.set(i, urlEncodeWithUtf8(valueParts.get(i))); } } } catch (UnsupportedEncodingException e1) { SoapUI.logError(e1); value = urlEncodeWithUtf8(value); for (int i = 0; i < valueParts.size(); i++) { valueParts.set(i, urlEncodeWithUtf8(valueParts.get(i))); } } // URLEncoder replaces space with "+", but we want "%20". value = value.replaceAll("\\+", "%20"); for (int i = 0; i < valueParts.size(); i++) { valueParts.set(i, valueParts.get(i).replaceAll("\\+", "%20")); } } if (param.getStyle() == ParameterStyle.QUERY && !sendEmptyParameters(request)) { if (!StringUtils.hasContent(value) && !param.getRequired()) { continue; } } switch (param.getStyle()) { case HEADER: for (String valuePart : valueParts) { httpMethod.addHeader(param.getName(), valuePart); } break; case QUERY: if (formMp == null || !request.isPostQueryString()) { for (String valuePart : valueParts) { if (query.length() > 0) { query.append('&'); } query.append(urlEncodeWithUtf8(param.getName())); query.append('='); if (StringUtils.hasContent(valuePart)) { query.append(valuePart); } } } else { try { addFormMultipart(request, formMp, param.getName(), responseProperties.get(param.getName())); } catch (MessagingException e) { SoapUI.logError(e); } } break; case TEMPLATE: try { value = getEncodedValue(value, encoding, param.isDisableUrlEncoding(), request .getSettings().getBoolean(HttpSettings.ENCODED_URLS)); path = path.replaceAll("\\{" + param.getName() + "\\}", value == null ? "" : value); } catch (UnsupportedEncodingException e) { SoapUI.logError(e); } break; case MATRIX: try { value = getEncodedValue(value, encoding, param.isDisableUrlEncoding(), request .getSettings().getBoolean(HttpSettings.ENCODED_URLS)); } catch (UnsupportedEncodingException e) { SoapUI.logError(e); } if (param.getType().equals(XmlBoolean.type.getName())) { if (value.toUpperCase().equals("TRUE") || value.equals("1")) { path += ";" + param.getName(); } } else { path += ";" + param.getName(); if (StringUtils.hasContent(value)) { path += "=" + value; } } break; case PLAIN: break; } } if (request.getSettings().getBoolean(HttpSettings.FORWARD_SLASHES)) { path = PathUtils.fixForwardSlashesInPath(path); } if (PathUtils.isHttpPath(path)) { try { // URI(String) automatically URLencodes the input, so we need to // decode it first... URI uri = new URI(path, request.getSettings().getBoolean(HttpSettings.ENCODED_URLS)); context.setProperty(BaseHttpRequestTransport.REQUEST_URI, uri); java.net.URI oldUri = httpMethod.getURI(); httpMethod .setURI(HttpUtils.createUri(oldUri.getScheme(), oldUri.getRawUserInfo(), oldUri.getHost(), oldUri.getPort(), oldUri.getRawPath(), uri.getEscapedQuery(), oldUri.getRawFragment())); } catch (Exception e) { SoapUI.logError(e); } } else if (StringUtils.hasContent(path)) { try { java.net.URI oldUri = httpMethod.getURI(); String pathToSet = StringUtils.hasContent(oldUri.getRawPath()) && !"/".equals(oldUri.getRawPath()) ? oldUri.getRawPath() + path : path; java.net.URI newUri = URIUtils.createURI(oldUri.getScheme(), oldUri.getHost(), oldUri.getPort(), pathToSet, oldUri.getQuery(), oldUri.getFragment()); httpMethod.setURI(newUri); context.setProperty(BaseHttpRequestTransport.REQUEST_URI, new URI(newUri.toString(), request .getSettings().getBoolean(HttpSettings.ENCODED_URLS))); } catch (Exception e) { SoapUI.logError(e); } } if (query.length() > 0 && !request.isPostQueryString()) { try { java.net.URI oldUri = httpMethod.getURI(); httpMethod.setURI(URIUtils.createURI(oldUri.getScheme(), oldUri.getHost(), oldUri.getPort(), oldUri.getRawPath(), query.toString(), oldUri.getFragment())); } catch (Exception e) { SoapUI.logError(e); } } if (formMp != null) { // create request message try { if (request.hasRequestBody() && httpMethod instanceof HttpEntityEnclosingRequest) { String requestContent = PropertyExpander.expandProperties(context, request.getRequestContent(), request.isEntitizeProperties()); if (StringUtils.hasContent(requestContent)) { initRootPart(request, requestContent, formMp); } } for (Attachment attachment : request.getAttachments()) { MimeBodyPart part = new PreencodedMimeBodyPart("binary"); if (attachment instanceof FileAttachment<?>) { String name = attachment.getName(); if (StringUtils.hasContent(attachment.getContentID()) && !name.equals(attachment.getContentID())) { name = attachment.getContentID(); } part.setDisposition("form-data; name=\"" + name + "\"; filename=\"" + attachment.getName() + "\""); } else { part.setDisposition("form-data; name=\"" + attachment.getName() + "\""); } part.setDataHandler(new DataHandler(new AttachmentDataSource(attachment))); formMp.addBodyPart(part); } MimeMessage message = new MimeMessage(AttachmentUtils.JAVAMAIL_SESSION); message.setContent(formMp); message.saveChanges(); RestRequestMimeMessageRequestEntity mimeMessageRequestEntity = new RestRequestMimeMessageRequestEntity( message, request); ((HttpEntityEnclosingRequest) httpMethod).setEntity(mimeMessageRequestEntity); httpMethod.setHeader("Content-Type", mimeMessageRequestEntity.getContentType().getValue()); httpMethod.setHeader("MIME-Version", "1.0"); } catch (Throwable e) { SoapUI.logError(e); } } else if (request.hasRequestBody() && httpMethod instanceof HttpEntityEnclosingRequest) { if (StringUtils.hasContent(request.getMediaType())) { httpMethod.setHeader("Content-Type", getContentTypeHeader(request.getMediaType(), encoding)); } if (request.isPostQueryString()) { try { ((HttpEntityEnclosingRequest) httpMethod).setEntity(new StringEntity(query.toString())); } catch (UnsupportedEncodingException e) { SoapUI.logError(e); } } else { String requestContent = PropertyExpander.expandProperties(context, request.getRequestContent(), request.isEntitizeProperties()); List<Attachment> attachments = new ArrayList<Attachment>(); for (Attachment attachment : request.getAttachments()) { if (attachment.getContentType().equals(request.getMediaType())) { attachments.add(attachment); } } if (StringUtils.hasContent(requestContent) && attachments.isEmpty()) { try { byte[] content = encoding == null ? requestContent.getBytes() : requestContent.getBytes(encoding); ((HttpEntityEnclosingRequest) httpMethod).setEntity(new ByteArrayEntity(content)); } catch (UnsupportedEncodingException e) { ((HttpEntityEnclosingRequest) httpMethod).setEntity(new ByteArrayEntity(requestContent .getBytes())); } } else if (attachments.size() > 0) { try { MimeMultipart mp = null; if (StringUtils.hasContent(requestContent)) { mp = new MimeMultipart(); initRootPart(request, requestContent, mp); } else if (attachments.size() == 1) { ((HttpEntityEnclosingRequest) httpMethod).setEntity(new InputStreamEntity(attachments.get(0) .getInputStream(), -1)); httpMethod.setHeader("Content-Type", getContentTypeHeader(request.getMediaType(), encoding)); } if (((HttpEntityEnclosingRequest) httpMethod).getEntity() == null) { if (mp == null) { mp = new MimeMultipart(); } // init mimeparts AttachmentUtils.addMimeParts(request, attachments, mp, new StringToStringMap()); // create request message MimeMessage message = new MimeMessage(AttachmentUtils.JAVAMAIL_SESSION); message.setContent(mp); message.saveChanges(); RestRequestMimeMessageRequestEntity mimeMessageRequestEntity = new RestRequestMimeMessageRequestEntity( message, request); ((HttpEntityEnclosingRequest) httpMethod).setEntity(mimeMessageRequestEntity); httpMethod.setHeader("Content-Type", getContentTypeHeader(mimeMessageRequestEntity.getContentType().getValue(), encoding)); httpMethod.setHeader("MIME-Version", "1.0"); } } catch (Exception e) { SoapUI.logError(e); } } } } } private boolean sendEmptyParameters(HttpRequestInterface<?> request) { return request instanceof HttpTestRequest && ((HttpTestRequest) request).isSendEmptyParameters(); } private String getContentTypeHeader(String contentType, String encoding) { return (encoding == null || encoding.trim().length() == 0) ? contentType : contentType + ";charset=" + encoding; } private void addFormMultipart(HttpRequestInterface<?> request, MimeMultipart formMp, String name, String value) throws MessagingException { MimeBodyPart part = new MimeBodyPart(); if (value.startsWith("file:")) { String fileName = value.substring(5); File file = new File(fileName); part.setDisposition("form-data; name=\"" + name + "\"; filename=\"" + file.getName() + "\""); if (file.exists()) { part.setDataHandler(new DataHandler(new FileDataSource(file))); } else { for (Attachment attachment : request.getAttachments()) { if (attachment.getName().equals(fileName)) { part.setDataHandler(new DataHandler(new AttachmentDataSource(attachment))); break; } } } part.setHeader("Content-Type", ContentTypeHandler.getContentTypeFromFilename(file.getName())); part.setHeader("Content-Transfer-Encoding", "binary"); } else { part.setDisposition("form-data; name=\"" + name + "\""); part.setText(value, System.getProperty("soapui.request.encoding", request.getEncoding())); } formMp.addBodyPart(part); } protected void initRootPart(HttpRequestInterface<?> wsdlRequest, String requestContent, MimeMultipart mp) throws MessagingException { MimeBodyPart rootPart = new PreencodedMimeBodyPart("8bit"); // rootPart.setContentID( AttachmentUtils.ROOTPART_SOAPUI_ORG ); mp.addBodyPart(rootPart, 0); DataHandler dataHandler = new DataHandler(new RestRequestDataSource(wsdlRequest, requestContent)); rootPart.setDataHandler(dataHandler); } protected String getEncodedValue(String value, String encoding, boolean isDisableUrlEncoding, boolean isPreEncoded) throws UnsupportedEncodingException { if (value == null) { return ""; } // get default encoding if there is no encoding set if (!StringUtils.hasContent(encoding)) { encoding = System.getProperty("file.encoding"); } if (isAlreadyEncoded(value, encoding)) { // Already encoded so we don't do anything return value; } else if (isDisableUrlEncoding || isPreEncoded) { // If encoding is disabled or it is pre-encoded then we don't encode return value; } else { // encoding NOT disabled neither it is pre-encoded, so we encode here String encodedValue = URLEncoder.encode(value, encoding); // URLEncoder replaces space with "+", but we want "%20". return encodedValue.replaceAll("\\+", "%20"); } } protected boolean isAlreadyEncoded(String path, String encoding) throws UnsupportedEncodingException { String decodedPath = java.net.URLDecoder.decode(path, encoding); return !path.equals(decodedPath); } }