View | Details | Raw Unified | Return to bug 52674
Collapse All | Expand All

(-)src/protocol/http/org/apache/jmeter/protocol/http/proxy/DefaultSamplerCreator.java (+349 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.protocol.http.proxy;
20
21
import java.io.File;
22
import java.io.IOException;
23
import java.net.MalformedURLException;
24
import java.net.URL;
25
import java.util.Map;
26
27
import org.apache.commons.io.FileUtils;
28
import org.apache.commons.lang.StringUtils;
29
import org.apache.jmeter.protocol.http.config.MultipartUrlConfig;
30
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
31
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
32
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerFactory;
33
import org.apache.jmeter.protocol.http.sampler.PostWriter;
34
import org.apache.jmeter.protocol.http.util.ConversionUtils;
35
import org.apache.jmeter.protocol.http.util.HTTPConstants;
36
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
37
import org.apache.jmeter.testelement.TestElement;
38
import org.apache.jorphan.logging.LoggingManager;
39
import org.apache.log.Logger;
40
41
/**
42
 * Default implementation that handles classical HTTP textual + Multipart requests
43
 */
44
public class DefaultSamplerCreator extends AbstractSamplerCreator {
45
    private static final Logger log = LoggingManager.getLoggerForClass();
46
 
47
    /**
48
     * 
49
     */
50
    public DefaultSamplerCreator() {
51
    }
52
53
    /**
54
     * @see org.apache.jmeter.protocol.http.proxy.SamplerCreator#getManagedContentTypes()
55
     */
56
    public String[] getManagedContentTypes() {
57
        return new String[0];
58
    }
59
60
    /**
61
     * 
62
     * @see org.apache.jmeter.protocol.http.proxy.SamplerCreator#createSampler(org.apache.jmeter.protocol.http.proxy.HttpRequestHdr, java.util.Map, java.util.Map)
63
     */
64
    public HTTPSamplerBase createSampler(HttpRequestHdr request,
65
            Map<String, String> pageEncodings, Map<String, String> formEncodings) {
66
        // Instantiate the sampler
67
        HTTPSamplerBase sampler = HTTPSamplerFactory.newInstance(request.getHttpSamplerName());
68
69
        sampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
70
71
        // Defaults
72
        sampler.setFollowRedirects(false);
73
        sampler.setUseKeepAlive(true);
74
75
        if (log.isDebugEnabled()) {
76
            log.debug("getSampler: sampler path = " + sampler.getPath());
77
        }
78
        return sampler;
79
    }
80
81
    /**
82
     * @see org.apache.jmeter.protocol.http.proxy.SamplerCreator#populateSampler(org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase, org.apache.jmeter.protocol.http.proxy.HttpRequestHdr, java.util.Map, java.util.Map)
83
     */
84
    public final void populateSampler(HTTPSamplerBase sampler,
85
            HttpRequestHdr request, Map<String, String> pageEncodings,
86
            Map<String, String> formEncodings) throws Exception{
87
        computeFromHeader(sampler, request, pageEncodings, formEncodings);
88
89
        computeFromPostBody(sampler, request);
90
        if (log.isDebugEnabled()) {
91
            log.debug("sampler path = " + sampler.getPath());
92
        }
93
    }
94
95
    /**
96
     * Compute sampler informations from Request Header
97
     * @param sampler {@link HTTPSamplerBase}
98
     * @param request {@link HttpRequestHdr}
99
     * @param pageEncodings Map<String, String>
100
     * @param formEncodings Map<String, String>
101
     * @throws Exception
102
     */
103
    protected void computeFromHeader(HTTPSamplerBase sampler,
104
            HttpRequestHdr request, Map<String, String> pageEncodings,
105
            Map<String, String> formEncodings) throws Exception {
106
        computeDomain(sampler, request);
107
        
108
        computeMethod(sampler, request);
109
        
110
        computePort(sampler, request);
111
        
112
        computeProtocol(sampler, request);
113
114
        computeContentEncoding(sampler, request,
115
                pageEncodings, formEncodings);
116
117
        computePath(sampler, request);
118
        
119
        computeSamplerName(sampler, request);
120
    }
121
122
    /**
123
     * Compute sampler informations from Request Header
124
     * @param sampler {@link HTTPSamplerBase}
125
     * @param request {@link HttpRequestHdr}
126
     * @throws Exception
127
     */
128
    protected void computeFromPostBody(HTTPSamplerBase sampler,
129
            HttpRequestHdr request) throws Exception {
130
        // If it was a HTTP GET request, then all parameters in the URL
131
        // has been handled by the sampler.setPath above, so we just need
132
        // to do parse the rest of the request if it is not a GET request
133
        if((!HTTPConstants.CONNECT.equals(request.getMethod())) && (!HTTPConstants.GET.equals(request.getMethod()))) {
134
            // Check if it was a multipart http post request
135
            final String contentType = request.getContentType();
136
            MultipartUrlConfig urlConfig = request.getMultipartConfig(contentType);
137
            String contentEncoding = sampler.getContentEncoding();
138
            // Get the post data using the content encoding of the request
139
            String postData = null;
140
            if (log.isDebugEnabled()) {
141
                if(!StringUtils.isEmpty(contentEncoding)) {
142
                    log.debug("Using encoding " + contentEncoding + " for request body");
143
                }
144
                else {
145
                    log.debug("No encoding found, using JRE default encoding for request body");
146
                }
147
            }
148
            
149
            
150
            if (!StringUtils.isEmpty(contentEncoding)) {
151
                postData = new String(request.getRawPostData(), contentEncoding);
152
            } else {
153
                // Use default encoding
154
                postData = new String(request.getRawPostData(), PostWriter.ENCODING);
155
            }
156
            
157
            if (urlConfig != null) {
158
                urlConfig.parseArguments(postData);
159
                // Tell the sampler to do a multipart post
160
                sampler.setDoMultipartPost(true);
161
                // Remove the header for content-type and content-length, since
162
                // those values will most likely be incorrect when the sampler
163
                // performs the multipart request, because the boundary string
164
                // will change
165
                request.getHeaderManager().removeHeaderNamed(HttpRequestHdr.CONTENT_TYPE);
166
                request.getHeaderManager().removeHeaderNamed(HttpRequestHdr.CONTENT_LENGTH);
167
168
                // Set the form data
169
                sampler.setArguments(urlConfig.getArguments());
170
                // Set the file uploads
171
                sampler.setHTTPFiles(urlConfig.getHTTPFileArgs().asArray());
172
            // used when postData is pure xml (eg. an xml-rpc call) or for PUT
173
            } else if (postData.trim().startsWith("<?") || "PUT".equals(sampler.getMethod())) {
174
                sampler.addNonEncodedArgument("", postData, "");
175
            } else if (contentType == null || contentType.startsWith(HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED) ){
176
                // It is the most common post request, with parameter name and values
177
                // We also assume this if no content type is present, to be most backwards compatible,
178
                // but maybe we should only parse arguments if the content type is as expected
179
                sampler.parseArguments(postData.trim(), contentEncoding); //standard name=value postData
180
            } else if (postData.length() > 0) {
181
                if (isBinaryContent(contentType)) {
182
                    try {
183
                        File tempDir = new File(getBinaryDirectory());
184
                        File out = File.createTempFile(request.getMethod(), getBinaryFileSuffix(), tempDir);
185
                        FileUtils.writeByteArrayToFile(out,request.getRawPostData());
186
                        HTTPFileArg [] files = {new HTTPFileArg(out.getPath(),"",contentType)};
187
                        sampler.setHTTPFiles(files);
188
                    } catch (IOException e) {
189
                        log.warn("Could not create binary file: "+e);
190
                    }
191
                } else {
192
                    // Just put the whole postbody as the value of a parameter
193
                    sampler.addNonEncodedArgument("", postData, ""); //used when postData is pure xml (ex. an xml-rpc call)
194
                }
195
            }
196
        }
197
    }
198
199
    /**
200
     * Compute sampler name
201
     * @param sampler {@link HTTPSamplerBase}
202
     * @param request {@link HttpRequestHdr}
203
     */
204
    protected void computeSamplerName(HTTPSamplerBase sampler,
205
            HttpRequestHdr request) {
206
        if (!HTTPConstants.CONNECT.equals(request.getMethod()) && isNumberRequests()) {
207
            incrementRequestNumber();
208
            sampler.setName(getRequestNumber() + " " + sampler.getPath());
209
        } else {
210
            sampler.setName(sampler.getPath());
211
        }
212
    }
213
214
    /**
215
     * Set path on sampler
216
     * @param sampler {@link HTTPSamplerBase}
217
     * @param request {@link HttpRequestHdr}
218
     */
219
    protected void computePath(HTTPSamplerBase sampler, HttpRequestHdr request) {
220
        if(sampler.getContentEncoding() != null) {
221
            sampler.setPath(request.getPath(), sampler.getContentEncoding());
222
        }
223
        else {
224
            // Although the spec says UTF-8 should be used for encoding URL parameters,
225
            // most browser use ISO-8859-1 for default if encoding is not known.
226
            // We use null for contentEncoding, then the url parameters will be added
227
            // with the value in the URL, and the "encode?" flag set to false
228
            sampler.setPath(request.getPath(), null);
229
        }
230
        if (log.isDebugEnabled()) {
231
            log.debug("Proxy: setting path: " + sampler.getPath());
232
        }
233
    }
234
235
    /**
236
     * Compute content encoding
237
     * @param sampler {@link HTTPSamplerBase}
238
     * @param request {@link HttpRequestHdr}
239
     * @param pageEncodings Map<String, String>
240
     * @param formEncodings Map<String, String>
241
     * @throws MalformedURLException
242
     */
243
    protected void computeContentEncoding(HTTPSamplerBase sampler,
244
            HttpRequestHdr request, Map<String, String> pageEncodings,
245
            Map<String, String> formEncodings) throws MalformedURLException {
246
        URL pageUrl = null;
247
        if(sampler.isProtocolDefaultPort()) {
248
            pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(), request.getPath());
249
        }
250
        else {
251
            pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(), 
252
                    sampler.getPort(), request.getPath());
253
        }
254
        String urlWithoutQuery = request.getUrlWithoutQuery(pageUrl);
255
256
257
        String contentEncoding = computeContentEncoding(request, pageEncodings,
258
                formEncodings, urlWithoutQuery);
259
        
260
        // Set the content encoding
261
        if(!StringUtils.isEmpty(contentEncoding)) {
262
            sampler.setContentEncoding(contentEncoding);
263
        } 
264
    }
265
    
266
    /**
267
     * Computes content encoding from request and if not found uses pageEncoding 
268
     * and formEncoding to see if URL was previously computed with a content type
269
     * @param sampler {@link HTTPSamplerBase}
270
     * @param request {@link HttpRequestHdr}
271
     * @param pageEncodings Map<String, String>
272
     * @param formEncodings Map<String, String>
273
     * @return String content encoding
274
     */
275
    protected String computeContentEncoding(HttpRequestHdr request,
276
            Map<String, String> pageEncodings,
277
            Map<String, String> formEncodings, String urlWithoutQuery) {
278
        // Check if the request itself tells us what the encoding is
279
        String contentEncoding = null;
280
        String requestContentEncoding = ConversionUtils.getEncodingFromContentType(
281
                request.getContentType());
282
        if(requestContentEncoding != null) {
283
            contentEncoding = requestContentEncoding;
284
        }
285
        else {
286
            // Check if we know the encoding of the page
287
            if (pageEncodings != null) {
288
                synchronized (pageEncodings) {
289
                    contentEncoding = pageEncodings.get(urlWithoutQuery);
290
                }
291
            }
292
            // Check if we know the encoding of the form
293
            if (formEncodings != null) {
294
                synchronized (formEncodings) {
295
                    String formEncoding = formEncodings.get(urlWithoutQuery);
296
                    // Form encoding has priority over page encoding
297
                    if (formEncoding != null) {
298
                        contentEncoding = formEncoding;
299
                    }
300
                }
301
            }
302
        }
303
        return contentEncoding;
304
    }
305
306
    /**
307
     * Set protocol on sampler
308
     * @param sampler {@link HTTPSamplerBase}
309
     * @param request {@link HttpRequestHdr}
310
     */
311
    protected void computeProtocol(HTTPSamplerBase sampler,
312
            HttpRequestHdr request) {
313
        sampler.setProtocol(request.getProtocol(sampler));
314
    }
315
316
    /**
317
     * Set Port on sampler
318
     * @param sampler {@link HTTPSamplerBase}
319
     * @param request {@link HttpRequestHdr}
320
     */
321
    protected void computePort(HTTPSamplerBase sampler, HttpRequestHdr request) {
322
        sampler.setPort(request.serverPort());
323
        if (log.isDebugEnabled()) {
324
            log.debug("Proxy: setting port: " + sampler.getPort());
325
        }
326
    }
327
328
    /**
329
     * Set method on sampler
330
     * @param sampler {@link HTTPSamplerBase}
331
     * @param request {@link HttpRequestHdr}
332
     */
333
    protected void computeMethod(HTTPSamplerBase sampler, HttpRequestHdr request) {
334
        sampler.setMethod(request.getMethod());
335
        log.debug("Proxy: setting method: " + sampler.getMethod());
336
    }
337
338
    /**
339
     * Set domain on sampler
340
     * @param sampler {@link HTTPSamplerBase}
341
     * @param request {@link HttpRequestHdr}
342
     */
343
    protected void computeDomain(HTTPSamplerBase sampler, HttpRequestHdr request) {
344
        sampler.setDomain(request.serverName());
345
        if (log.isDebugEnabled()) {
346
            log.debug("Proxy: setting server: " + sampler.getDomain());
347
        }
348
    }
349
}
(-)src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreator.java (+57 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.protocol.http.proxy;
20
21
import java.util.Map;
22
23
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
24
25
/**
26
 * Factory of sampler
27
 */
28
public interface SamplerCreator {
29
    
30
    /**
31
     * @return String[] array of Content types managed by Factory
32
     */
33
    public String[] getManagedContentTypes();
34
35
    /**
36
     * Create HTTPSamplerBase
37
     * @param request {@link HttpRequestHdr}
38
     * @param pageEncodings Map<String, String>
39
     * @param formEncodings Map<String, String>
40
     * @return {@link HTTPSamplerBase}
41
     */
42
    public HTTPSamplerBase createSampler(HttpRequestHdr request,
43
            Map<String, String> pageEncodings, Map<String, String> formEncodings);
44
45
    /**
46
     * Populate sampler from request
47
     * @param sampler {@link HTTPSamplerBase}
48
     * @param request {@link HttpRequestHdr}
49
     * @param pageEncodings Map<String, String>
50
     * @param formEncodings Map<String, String>
51
     * @throws Exception
52
     */
53
    public void populateSampler(HTTPSamplerBase sampler,
54
            HttpRequestHdr request, Map<String, String> pageEncodings,
55
            Map<String, String> formEncodings)
56
                    throws Exception;
57
}
(-)src/protocol/http/org/apache/jmeter/protocol/http/proxy/AbstractSamplerCreator.java (+123 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.protocol.http.proxy;
20
21
import java.util.HashSet;
22
import java.util.Set;
23
import java.util.StringTokenizer;
24
25
import org.apache.jmeter.util.JMeterUtils;
26
27
/**
28
 * Base class for SamplerCreator
29
 */
30
public abstract class AbstractSamplerCreator implements SamplerCreator {
31
32
    protected static final String HTTP = "http"; // $NON-NLS-1$
33
    protected static final String HTTPS = "https"; // $NON-NLS-1$
34
35
    /** Filetype to be used for the temporary binary files*/
36
    private static final String binaryFileSuffix =
37
        JMeterUtils.getPropDefault("proxy.binary.filesuffix",// $NON-NLS-1$
38
                                   ".binary"); // $NON-NLS-1$
39
40
    /** Which content-types will be treated as binary (exact match) */
41
    private static final Set<String> binaryContentTypes = new HashSet<String>();
42
43
    /** Where to store the temporary binary files */
44
    private static final String binaryDirectory =
45
        JMeterUtils.getPropDefault("proxy.binary.directory",// $NON-NLS-1$
46
                System.getProperty("user.dir")); // $NON-NLS-1$ proxy.binary.filetype=binary
47
48
    static {
49
        String binaries = JMeterUtils.getPropDefault("proxy.binary.types", // $NON-NLS-1$
50
                "application/x-amf,application/x-java-serialized-object"); // $NON-NLS-1$
51
        if (binaries.length() > 0){
52
            StringTokenizer s = new StringTokenizer(binaries,"|, ");// $NON-NLS-1$
53
            while (s.hasMoreTokens()){
54
               binaryContentTypes.add(s.nextToken());
55
            }
56
        }
57
    }
58
    
59
    /*
60
     * Optionally number the requests
61
     */
62
    private static final boolean numberRequests =
63
        JMeterUtils.getPropDefault("proxy.number.requests", false); // $NON-NLS-1$
64
65
    private static volatile int requestNumber = 0;// running number
66
    
67
68
    /**
69
     * 
70
     */
71
    /**
72
     * 
73
     */
74
    public AbstractSamplerCreator() {
75
        super();
76
    }
77
78
    /**
79
     * @return int request number
80
     */
81
    protected static int getRequestNumber() {
82
        return requestNumber;
83
    }
84
85
    /**
86
     * Increment request number
87
     */
88
    protected static void incrementRequestNumber() {
89
        requestNumber++;
90
    }
91
92
    /**
93
     * @return boolean is numbering requests is required
94
     */
95
    protected static boolean isNumberRequests() {
96
        return numberRequests;
97
    }
98
99
    /**
100
     * @param contentType String content type
101
     * @return true if contentType is part of binary declared types
102
     */
103
    protected boolean isBinaryContent(String contentType) {
104
        if (contentType == null) {
105
            return false;
106
        }
107
        return binaryContentTypes.contains(contentType);
108
    }
109
    
110
    /**
111
     * @return String binary file suffix
112
     */
113
    protected String getBinaryFileSuffix() {
114
        return binaryFileSuffix;
115
    }
116
117
    /**
118
     * @return String binary directory
119
     */
120
    protected String getBinaryDirectory() {
121
        return binaryDirectory;
122
    }
123
}
(-)src/protocol/http/org/apache/jmeter/protocol/http/proxy/HttpRequestHdr.java (-234 / +46 lines)
Lines 19-48 Link Here
19
package org.apache.jmeter.protocol.http.proxy;
19
package org.apache.jmeter.protocol.http.proxy;
20
20
21
import java.io.ByteArrayOutputStream;
21
import java.io.ByteArrayOutputStream;
22
import java.io.File;
23
import java.io.IOException;
22
import java.io.IOException;
24
import java.io.InputStream;
23
import java.io.InputStream;
25
import java.io.UnsupportedEncodingException;
26
import java.net.MalformedURLException;
27
import java.net.URL;
24
import java.net.URL;
28
import java.util.HashMap;
25
import java.util.HashMap;
29
import java.util.HashSet;
30
import java.util.Map;
26
import java.util.Map;
31
import java.util.Set;
32
import java.util.StringTokenizer;
27
import java.util.StringTokenizer;
33
28
34
import org.apache.commons.io.FileUtils;
35
import org.apache.commons.lang.CharUtils;
29
import org.apache.commons.lang.CharUtils;
36
import org.apache.jmeter.protocol.http.config.MultipartUrlConfig;
30
import org.apache.jmeter.protocol.http.config.MultipartUrlConfig;
37
import org.apache.jmeter.protocol.http.control.Header;
31
import org.apache.jmeter.protocol.http.control.Header;
38
import org.apache.jmeter.protocol.http.control.HeaderManager;
32
import org.apache.jmeter.protocol.http.control.HeaderManager;
39
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
40
import org.apache.jmeter.protocol.http.gui.HeaderPanel;
33
import org.apache.jmeter.protocol.http.gui.HeaderPanel;
41
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
34
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
42
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerFactory;
43
import org.apache.jmeter.protocol.http.util.ConversionUtils;
44
import org.apache.jmeter.protocol.http.util.HTTPConstants;
35
import org.apache.jmeter.protocol.http.util.HTTPConstants;
45
import org.apache.jmeter.protocol.http.util.HTTPFileArg;
46
import org.apache.jmeter.testelement.TestElement;
36
import org.apache.jmeter.testelement.TestElement;
47
import org.apache.jmeter.util.JMeterUtils;
37
import org.apache.jmeter.util.JMeterUtils;
48
import org.apache.jorphan.logging.LoggingManager;
38
import org.apache.jorphan.logging.LoggingManager;
Lines 60-91 Link Here
60
    private static final String HTTP = "http"; // $NON-NLS-1$
50
    private static final String HTTP = "http"; // $NON-NLS-1$
61
    private static final String HTTPS = "https"; // $NON-NLS-1$
51
    private static final String HTTPS = "https"; // $NON-NLS-1$
62
    private static final String PROXY_CONNECTION = "proxy-connection"; // $NON-NLS-1$
52
    private static final String PROXY_CONNECTION = "proxy-connection"; // $NON-NLS-1$
63
    private static final String CONTENT_TYPE = "content-type"; // $NON-NLS-1$
53
    public static final String CONTENT_TYPE = "content-type"; // $NON-NLS-1$
64
    private static final String CONTENT_LENGTH = "content-length"; // $NON-NLS-1$
54
    public static final String CONTENT_LENGTH = "content-length"; // $NON-NLS-1$
65
66
    /** Filetype to be used for the temporary binary files*/
67
    private static final String binaryFileSuffix =
68
        JMeterUtils.getPropDefault("proxy.binary.filesuffix",// $NON-NLS-1$
69
                                   ".binary"); // $NON-NLS-1$
70
71
    /** Which content-types will be treated as binary (exact match) */
72
    private static final Set<String> binaryContentTypes = new HashSet<String>();
73
55
74
    /** Where to store the temporary binary files */
75
    private static final String binaryDirectory =
76
        JMeterUtils.getPropDefault("proxy.binary.directory",// $NON-NLS-1$
77
                System.getProperty("user.dir")); // $NON-NLS-1$ proxy.binary.filetype=binary
78
79
    static {
80
        String binaries = JMeterUtils.getPropDefault("proxy.binary.types", // $NON-NLS-1$
81
                "application/x-amf,application/x-java-serialized-object"); // $NON-NLS-1$
82
        if (binaries.length() > 0){
83
            StringTokenizer s = new StringTokenizer(binaries,"|, ");// $NON-NLS-1$
84
            while (s.hasMoreTokens()){
85
               binaryContentTypes.add(s.nextToken());
86
            }
87
        }
88
    }
89
56
90
    /**
57
    /**
91
     * Http Request method, uppercased, e.g. GET or POST.
58
     * Http Request method, uppercased, e.g. GET or POST.
Lines 114-127 Link Here
114
81
115
    private HeaderManager headerManager;
82
    private HeaderManager headerManager;
116
83
117
    /*
118
     * Optionally number the requests
119
     */
120
    private static final boolean numberRequests =
121
        JMeterUtils.getPropDefault("proxy.number.requests", false); // $NON-NLS-1$
122
123
    private static volatile int requestNumber = 0;// running number
124
125
    public HttpRequestHdr() {
84
    public HttpRequestHdr() {
126
        this.httpSamplerName = ""; // $NON-NLS-1$
85
        this.httpSamplerName = ""; // $NON-NLS-1$
127
    }
86
    }
Lines 251-276 Link Here
251
        return headerManager;
210
        return headerManager;
252
    }
211
    }
253
212
254
    public HTTPSamplerBase getSampler(Map<String, String> pageEncodings, Map<String, String> formEncodings)
213
    public String getContentType() {
255
            throws MalformedURLException, IOException {
256
        // Instantiate the sampler
257
        HTTPSamplerBase sampler = HTTPSamplerFactory.newInstance(httpSamplerName);
258
        sampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
259
260
        // Populate the sampler
261
        populateSampler(sampler, pageEncodings, formEncodings);
262
263
        // Defaults
264
        sampler.setFollowRedirects(false);
265
        sampler.setUseKeepAlive(true);
266
267
        if (log.isDebugEnabled()) {
268
            log.debug("getSampler: sampler path = " + sampler.getPath());
269
        }
270
        return sampler;
271
    }
272
273
    private String getContentType() {
274
        Header contentTypeHeader = headers.get(CONTENT_TYPE);
214
        Header contentTypeHeader = headers.get(CONTENT_TYPE);
275
        if (contentTypeHeader != null) {
215
        if (contentTypeHeader != null) {
276
            return contentTypeHeader.getValue();
216
            return contentTypeHeader.getValue();
Lines 285-291 Link Here
285
        return false;
225
        return false;
286
    }
226
    }
287
227
288
    private MultipartUrlConfig getMultipartConfig(String contentType) {
228
    public MultipartUrlConfig getMultipartConfig(String contentType) {
289
        if(isMultipart(contentType)) {
229
        if(isMultipart(contentType)) {
290
            // Get the boundary string for the multiparts from the content type
230
            // Get the boundary string for the multiparts from the content type
291
            String boundaryString = contentType.substring(contentType.toLowerCase(java.util.Locale.ENGLISH).indexOf("boundary=") + "boundary=".length());
231
            String boundaryString = contentType.substring(contentType.toLowerCase(java.util.Locale.ENGLISH).indexOf("boundary=") + "boundary=".length());
Lines 294-465 Link Here
294
        return null;
234
        return null;
295
    }
235
    }
296
236
297
    private void populateSampler(
298
            HTTPSamplerBase sampler,
299
            Map<String, String> pageEncodings, Map<String, String> formEncodings)
300
            throws MalformedURLException, UnsupportedEncodingException {
301
        sampler.setDomain(serverName());
302
        if (log.isDebugEnabled()) {
303
            log.debug("Proxy: setting server: " + sampler.getDomain());
304
        }
305
        sampler.setMethod(method);
306
        log.debug("Proxy: setting method: " + sampler.getMethod());
307
        sampler.setPort(serverPort());
308
        if (log.isDebugEnabled()) {
309
            log.debug("Proxy: setting port: " + sampler.getPort());
310
        }
311
        if (url.indexOf("//") > -1) {
312
            String protocol = url.substring(0, url.indexOf(":"));
313
            if (log.isDebugEnabled()) {
314
                log.debug("Proxy: setting protocol to : " + protocol);
315
            }
316
            sampler.setProtocol(protocol);
317
        } else if (sampler.getPort() == HTTPConstants.DEFAULT_HTTPS_PORT) {
318
            sampler.setProtocol(HTTPS);
319
            if (log.isDebugEnabled()) {
320
                log.debug("Proxy: setting protocol to https");
321
            }
322
        } else {
323
            if (log.isDebugEnabled()) {
324
                log.debug("Proxy setting default protocol to: http");
325
            }
326
            sampler.setProtocol(HTTP);
327
        }
328
329
        URL pageUrl = null;
330
        if(sampler.isProtocolDefaultPort()) {
331
            pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(), getPath());
332
        }
333
        else {
334
            pageUrl = new URL(sampler.getProtocol(), sampler.getDomain(), sampler.getPort(), getPath());
335
        }
336
        String urlWithoutQuery = getUrlWithoutQuery(pageUrl);
337
338
339
        // Check if the request itself tells us what the encoding is
340
        String contentEncoding = null;
341
        String requestContentEncoding = ConversionUtils.getEncodingFromContentType(getContentType());
342
        if(requestContentEncoding != null) {
343
            contentEncoding = requestContentEncoding;
344
        }
345
        else {
346
            // Check if we know the encoding of the page
347
            if (pageEncodings != null) {
348
                synchronized (pageEncodings) {
349
                    contentEncoding = pageEncodings.get(urlWithoutQuery);
350
                }
351
            }
352
            // Check if we know the encoding of the form
353
            if (formEncodings != null) {
354
                synchronized (formEncodings) {
355
                    String formEncoding = formEncodings.get(urlWithoutQuery);
356
                    // Form encoding has priority over page encoding
357
                    if (formEncoding != null) {
358
                        contentEncoding = formEncoding;
359
                    }
360
                }
361
            }
362
        }
363
364
        // Get the post data using the content encoding of the request
365
        String postData = null;
366
        if (log.isDebugEnabled()) {
367
            if(contentEncoding != null) {
368
                log.debug("Using encoding " + contentEncoding + " for request body");
369
            }
370
            else {
371
                log.debug("No encoding found, using JRE default encoding for request body");
372
            }
373
        }
374
        if (contentEncoding != null) {
375
            postData = new String(rawPostData, contentEncoding);
376
        } else {
377
            // Use default encoding
378
            postData = new String(rawPostData);
379
        }
380
381
        if(contentEncoding != null) {
382
            sampler.setPath(getPath(), contentEncoding);
383
        }
384
        else {
385
            // Although the spec says UTF-8 should be used for encoding URL parameters,
386
            // most browser use ISO-8859-1 for default if encoding is not known.
387
            // We use null for contentEncoding, then the url parameters will be added
388
            // with the value in the URL, and the "encode?" flag set to false
389
            sampler.setPath(getPath(), null);
390
        }
391
        if (log.isDebugEnabled()) {
392
            log.debug("Proxy: setting path: " + sampler.getPath());
393
        }
394
        if (!HTTPConstants.CONNECT.equals(getMethod()) && numberRequests) {
395
            requestNumber++;
396
            sampler.setName(requestNumber + " " + sampler.getPath());
397
        } else {
398
            sampler.setName(sampler.getPath());
399
        }
400
401
        // Set the content encoding
402
        if(contentEncoding != null) {
403
            sampler.setContentEncoding(contentEncoding);
404
        }
405
406
        // If it was a HTTP GET request, then all parameters in the URL
407
        // has been handled by the sampler.setPath above, so we just need
408
        // to do parse the rest of the request if it is not a GET request
409
        if((!HTTPConstants.CONNECT.equals(getMethod())) && (!HTTPConstants.GET.equals(method))) {
410
            // Check if it was a multipart http post request
411
            final String contentType = getContentType();
412
            MultipartUrlConfig urlConfig = getMultipartConfig(contentType);
413
            if (urlConfig != null) {
414
                urlConfig.parseArguments(postData);
415
                // Tell the sampler to do a multipart post
416
                sampler.setDoMultipartPost(true);
417
                // Remove the header for content-type and content-length, since
418
                // those values will most likely be incorrect when the sampler
419
                // performs the multipart request, because the boundary string
420
                // will change
421
                getHeaderManager().removeHeaderNamed(CONTENT_TYPE);
422
                getHeaderManager().removeHeaderNamed(CONTENT_LENGTH);
423
424
                // Set the form data
425
                sampler.setArguments(urlConfig.getArguments());
426
                // Set the file uploads
427
                sampler.setHTTPFiles(urlConfig.getHTTPFileArgs().asArray());
428
            // used when postData is pure xml (eg. an xml-rpc call) or for PUT
429
            } else if (postData.trim().startsWith("<?") || "PUT".equals(sampler.getMethod())) {
430
                sampler.addNonEncodedArgument("", postData, "");
431
            } else if (contentType == null || contentType.startsWith(HTTPConstants.APPLICATION_X_WWW_FORM_URLENCODED) ){
432
                // It is the most common post request, with parameter name and values
433
                // We also assume this if no content type is present, to be most backwards compatible,
434
                // but maybe we should only parse arguments if the content type is as expected
435
                sampler.parseArguments(postData.trim(), contentEncoding); //standard name=value postData
436
            } else if (postData.length() > 0) {
437
                if (isBinaryContent(contentType)) {
438
                    try {
439
                        File tempDir = new File(binaryDirectory);
440
                        File out = File.createTempFile(method, binaryFileSuffix, tempDir);
441
                        FileUtils.writeByteArrayToFile(out,rawPostData);
442
                        HTTPFileArg [] files = {new HTTPFileArg(out.getPath(),"",contentType)};
443
                        sampler.setHTTPFiles(files);
444
                    } catch (IOException e) {
445
                        log.warn("Could not create binary file: "+e);
446
                    }
447
                } else {
448
                    // Just put the whole postbody as the value of a parameter
449
                    sampler.addNonEncodedArgument("", postData, ""); //used when postData is pure xml (ex. an xml-rpc call)
450
                }
451
            }
452
        }
453
        if (log.isDebugEnabled()) {
454
            log.debug("sampler path = " + sampler.getPath());
455
        }
456
    }
457
458
    private boolean isBinaryContent(String contentType) {
459
        if (contentType == null) return false;
460
        return binaryContentTypes.contains(contentType);
461
    }
462
463
    //
237
    //
464
    // Parsing Methods
238
    // Parsing Methods
465
    //
239
    //
Lines 469-475 Link Here
469
     *
243
     *
470
     * @return server's internet name
244
     * @return server's internet name
471
     */
245
     */
472
    private String serverName() {
246
    public String serverName() {
473
        // chop to "server.name:x/thing"
247
        // chop to "server.name:x/thing"
474
        String str = url;
248
        String str = url;
475
        int i = str.indexOf("//"); // $NON-NLS-1$
249
        int i = str.indexOf("//"); // $NON-NLS-1$
Lines 500-506 Link Here
500
     *
274
     *
501
     * @return server's port (or UNSPECIFIED if not found)
275
     * @return server's port (or UNSPECIFIED if not found)
502
     */
276
     */
503
    private int serverPort() {
277
    public int serverPort() {
504
        String str = url;
278
        String str = url;
505
        // chop to "server.name:x/thing"
279
        // chop to "server.name:x/thing"
506
        int i = str.indexOf("//");
280
        int i = str.indexOf("//");
Lines 525-531 Link Here
525
     *
299
     *
526
     * @return the path
300
     * @return the path
527
     */
301
     */
528
    private String getPath() {
302
    public String getPath() {
529
        String str = url;
303
        String str = url;
530
        int i = str.indexOf("//");
304
        int i = str.indexOf("//");
531
        if (i > 0) {
305
        if (i > 0) {
Lines 589-595 Link Here
589
//        return strBuff.toString();
363
//        return strBuff.toString();
590
//    }
364
//    }
591
365
592
    private String getUrlWithoutQuery(URL _url) {
366
    public String getUrlWithoutQuery(URL _url) {
593
        String fullUrl = _url.toString();
367
        String fullUrl = _url.toString();
594
        String urlWithoutQuery = fullUrl;
368
        String urlWithoutQuery = fullUrl;
595
        String query = _url.getQuery();
369
        String query = _url.getQuery();
Lines 599-602 Link Here
599
        }
373
        }
600
        return urlWithoutQuery;
374
        return urlWithoutQuery;
601
    }
375
    }
376
377
    /**
378
     * @return the httpSamplerName
379
     */
380
    public String getHttpSamplerName() {
381
        return httpSamplerName;
382
    }
383
384
    /**
385
     * @return byte[] Raw post data
386
     */
387
    public byte[] getRawPostData() {
388
        return rawPostData;
389
    }
390
391
    /**
392
     * @param sampler {@link HTTPSamplerBase}
393
     * @return String Protocol (http or https)
394
     */
395
    public String getProtocol(HTTPSamplerBase sampler) {
396
        if (url.indexOf("//") > -1) {
397
            String protocol = url.substring(0, url.indexOf(":"));
398
            if (log.isDebugEnabled()) {
399
                log.debug("Proxy: setting protocol to : " + protocol);
400
            }
401
            return protocol;
402
        } else if (sampler.getPort() == HTTPConstants.DEFAULT_HTTPS_PORT) {
403
            if (log.isDebugEnabled()) {
404
                log.debug("Proxy: setting protocol to https");
405
            }
406
            return HTTPS;
407
        } else {
408
            if (log.isDebugEnabled()) {
409
                log.debug("Proxy setting default protocol to: http");
410
            }
411
            return HTTP;
412
        }
413
    }
602
}
414
}
(-)src/protocol/http/org/apache/jmeter/protocol/http/proxy/Proxy.java (-4 / +6 lines)
Lines 109-114 Link Here
109
    private static final char[] KEY_PASSWORD =
109
    private static final char[] KEY_PASSWORD =
110
        JMeterUtils.getPropDefault("proxy.cert.keypassword","password").toCharArray(); // $NON-NLS-1$ $NON-NLS-2$
110
        JMeterUtils.getPropDefault("proxy.cert.keypassword","password").toCharArray(); // $NON-NLS-1$ $NON-NLS-2$
111
111
112
    private static final SamplerCreatorFactory factory = new SamplerCreatorFactory();
113
112
    // Use with SSL connection
114
    // Use with SSL connection
113
    private OutputStream outStreamClient = null;
115
    private OutputStream outStreamClient = null;
114
116
Lines 202-211 Link Here
202
                request.parse(new BufferedInputStream(clientSocket.getInputStream()));
204
                request.parse(new BufferedInputStream(clientSocket.getInputStream()));
203
            }
205
            }
204
206
205
            // Populate the sampler. It is the same sampler as we sent into
207
            SamplerCreator samplerCreator = factory.getSamplerCreator(request, pageEncodings, formEncodings);
206
            // the constructor of the HttpRequestHdr instance above
208
            sampler = samplerCreator.createSampler(request, pageEncodings, formEncodings);
207
            sampler = request.getSampler(pageEncodings, formEncodings);
209
            samplerCreator.populateSampler(sampler, request, pageEncodings, formEncodings);
208
210
            
209
            /*
211
            /*
210
             * Create a Header Manager to ensure that the browsers headers are
212
             * Create a Header Manager to ensure that the browsers headers are
211
             * captured and sent to the server
213
             * captured and sent to the server
(-)src/protocol/http/org/apache/jmeter/protocol/http/proxy/SamplerCreatorFactory.java (+95 lines)
Line 0 Link Here
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *   http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 *
17
 */
18
19
package org.apache.jmeter.protocol.http.proxy;
20
21
import java.lang.reflect.Modifier;
22
import java.util.HashMap;
23
import java.util.List;
24
import java.util.Map;
25
26
import org.apache.jmeter.util.JMeterUtils;
27
import org.apache.jorphan.logging.LoggingManager;
28
import org.apache.jorphan.reflect.ClassFinder;
29
import org.apache.log.Logger;
30
31
/**
32
 * {@link SamplerCreator} factory
33
 */
34
public class SamplerCreatorFactory {
35
    private static final Logger log = LoggingManager.getLoggerForClass();
36
37
    private static final SamplerCreator DEFAULT_SAMPLER_CREATOR = new DefaultSamplerCreator();
38
39
    private Map<String, SamplerCreator> samplerCreatorMap = new HashMap<String, SamplerCreator>();
40
41
    /**
42
     * 
43
     */
44
    public SamplerCreatorFactory() {
45
        init();
46
    }
47
    
48
    /**
49
     * Initialize factory from classpath
50
     */
51
    private void init() {
52
        try {
53
            List<String> listClasses = ClassFinder.findClassesThatExtend(
54
                    JMeterUtils.getSearchPaths(), 
55
                    new Class[] {SamplerCreator.class }); 
56
            for (String strClassName : listClasses) {
57
                try {
58
                    log.info("Loading class:"+ strClassName);
59
                    Class<?> commandClass = Class.forName(strClassName);
60
                    if (!Modifier.isAbstract(commandClass.getModifiers())) {
61
                            log.info("Instantiating :"+ commandClass.getName());
62
                            SamplerCreator creator = (SamplerCreator) commandClass.newInstance();
63
                            String[] contentTypes = creator.getManagedContentTypes();
64
                            for (String contentType : contentTypes) {
65
                                if(log.isInfoEnabled()) {
66
                                    log.info("Registering samplerCreator "+commandClass.getName()+" for content type:"+contentType);
67
                                }
68
                                samplerCreatorMap.put(contentType, creator);
69
                            }                        
70
                    }
71
                } catch (Exception e) {
72
                    log.error("Exception registering "+SamplerCreator.class.getName() + " with implementation:"+strClassName, e);
73
                }
74
            }
75
        } catch (Exception e) {
76
            log.error("Exception finding implementations of "+SamplerCreator.class, e);
77
        }
78
    }
79
80
    /**
81
     * Gets {@link SamplerCreator} for content type, if none is found returns {@link DefaultSamplerCreator}
82
     * @param request {@link HttpRequestHdr}
83
     * @param pageEncodings Map<String, String> pageEncodings
84
     * @param formEncodings  Map<String, String> formEncodings
85
     * @return SamplerCreator
86
     */
87
    public SamplerCreator getSamplerCreator(HttpRequestHdr request,
88
            Map<String, String> pageEncodings, Map<String, String> formEncodings) {
89
        SamplerCreator creator = samplerCreatorMap.get(request.getContentType());
90
        if(creator == null) {
91
            return DEFAULT_SAMPLER_CREATOR;
92
        }
93
        return creator;
94
    }
95
}
(-)test/src/org/apache/jmeter/protocol/http/proxy/TestHttpRequestHdr.java (-2 / +6 lines)
Lines 569-575 Link Here
569
    }
569
    }
570
570
571
    private HTTPSamplerBase getSamplerForRequest(String url, String request, String contentEncoding)
571
    private HTTPSamplerBase getSamplerForRequest(String url, String request, String contentEncoding)
572
            throws IOException {
572
            throws Exception {
573
        HttpRequestHdr req = new HttpRequestHdr();
573
        HttpRequestHdr req = new HttpRequestHdr();
574
        ByteArrayInputStream bis = null;
574
        ByteArrayInputStream bis = null;
575
        if(contentEncoding != null) {
575
        if(contentEncoding != null) {
Lines 587-593 Link Here
587
        if(url != null && contentEncoding != null) {
587
        if(url != null && contentEncoding != null) {
588
            pageEncodings.put(url, contentEncoding);
588
            pageEncodings.put(url, contentEncoding);
589
        }
589
        }
590
        return req.getSampler(pageEncodings, formEncodings);
590
        SamplerCreatorFactory creatorFactory = new SamplerCreatorFactory();
591
        SamplerCreator creator = creatorFactory.getSamplerCreator(req, pageEncodings, formEncodings);
592
        HTTPSamplerBase sampler = creator.createSampler(req, pageEncodings, formEncodings);
593
        creator.populateSampler(sampler, req, pageEncodings, formEncodings);
594
        return sampler;
591
    }
595
    }
592
    
596
    
593
    private void checkArgument(
597
    private void checkArgument(

Return to bug 52674