Source Code Cross Referenced for Proxy.java in  » Testing » jakarta-jmeter » org » apache » jmeter » protocol » http » proxy » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Testing » jakarta jmeter » org.apache.jmeter.protocol.http.proxy 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *   http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         * 
017:         */
018:
019:        package org.apache.jmeter.protocol.http.proxy;
020:
021:        import java.io.BufferedInputStream;
022:        import java.io.BufferedOutputStream;
023:        import java.io.DataOutputStream;
024:        import java.io.IOException;
025:        import java.io.OutputStream;
026:        import java.net.Socket;
027:        import java.net.UnknownHostException;
028:        import java.net.URL;
029:        import java.util.Map;
030:
031:        import org.apache.jmeter.protocol.http.control.HeaderManager;
032:        import org.apache.jmeter.protocol.http.parser.HTMLParseException;
033:        import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
034:        import org.apache.jmeter.protocol.http.sampler.HTTPSamplerFactory;
035:        import org.apache.jmeter.protocol.http.util.HTTPConstants;
036:        import org.apache.jmeter.samplers.SampleResult;
037:        import org.apache.jmeter.testelement.TestElement;
038:        import org.apache.jmeter.util.JMeterUtils;
039:        import org.apache.jorphan.logging.LoggingManager;
040:        import org.apache.jorphan.util.JOrphanUtils;
041:        import org.apache.log.Logger;
042:
043:        /**
044:         * Thread to handle one client request. Gets the request from the client and
045:         * passes it on to the server, then sends the response back to the client.
046:         * Information about the request and response is stored so it can be used in a
047:         * JMeter test plan.
048:         * 
049:         */
050:        public class Proxy extends Thread {
051:            private static final Logger log = LoggingManager
052:                    .getLoggerForClass();
053:
054:            private static final String NEW_LINE = "\n"; // $NON-NLS-1$
055:
056:            private static final String[] headersToRemove;
057:
058:            // Allow list of headers to be overridden
059:            private static final String PROXY_HEADERS_REMOVE = "proxy.headers.remove"; // $NON-NLS-1$
060:
061:            private static final String PROXY_HEADERS_REMOVE_DEFAULT = "If-Modified-Since,If-None-Match"; // $NON-NLS-1$
062:
063:            private static final String PROXY_HEADERS_REMOVE_SEPARATOR = ","; // $NON-NLS-1$
064:
065:            static {
066:                String removeList = JMeterUtils.getPropDefault(
067:                        PROXY_HEADERS_REMOVE, PROXY_HEADERS_REMOVE_DEFAULT);
068:                headersToRemove = JOrphanUtils.split(removeList,
069:                        PROXY_HEADERS_REMOVE_SEPARATOR);
070:                log.info("Proxy will remove the headers: " + removeList);
071:            }
072:
073:            /** Socket to client. */
074:            private Socket clientSocket = null;
075:
076:            /** Target to receive the generated sampler. */
077:            private ProxyControl target;
078:
079:            /** Whether or not to capture the HTTP headers. */
080:            private boolean captureHttpHeaders;
081:
082:            /** Whether to try to spoof as https **/
083:            private boolean httpsSpoof;
084:
085:            private String httpsSpoofMatch; // if non-empty, then URLs must match in order to be spoofed
086:
087:            /** Reference to Deamon's Map of url string to page character encoding of that page */
088:            private Map pageEncodings;
089:            /** Reference to Deamon's Map of url string to character encoding for the form */
090:            private Map formEncodings;
091:
092:            /**
093:             * Default constructor - used by newInstance call in Daemon
094:             */
095:            public Proxy() {
096:            }
097:
098:            /**
099:             * Create and configure a new Proxy object.
100:             * 
101:             * @param clientSocket
102:             *            the socket connection to the client
103:             * @param target
104:             *            the ProxyControl which will receive the generated sampler
105:             */
106:            Proxy(Socket clientSocket, ProxyControl target) {
107:                configure(clientSocket, target);
108:            }
109:
110:            /**
111:             * Configure the Proxy.
112:             * 
113:             * @param clientSocket
114:             *            the socket connection to the client
115:             * @param target
116:             *            the ProxyControl which will receive the generated sampler
117:             */
118:            void configure(Socket _clientSocket, ProxyControl _target) {
119:                configure(_clientSocket, _target, null, null);
120:            }
121:
122:            /**
123:             * Configure the Proxy.
124:             * 
125:             * @param _clientSocket
126:             *            the socket connection to the client
127:             * @param _target
128:             *            the ProxyControl which will receive the generated sampler
129:             * @param _pageEncodings
130:             *            reference to the Map of Deamon, with mappings from page urls to encoding used
131:             * @param formEncodingsEncodings
132:             *            reference to the Map of Deamon, with mappings from form action urls to encoding used
133:             */
134:            void configure(Socket _clientSocket, ProxyControl _target,
135:                    Map _pageEncodings, Map _formEncodings) {
136:                this .target = _target;
137:                this .clientSocket = _clientSocket;
138:                this .captureHttpHeaders = _target.getCaptureHttpHeaders();
139:                this .httpsSpoof = _target.getHttpsSpoof();
140:                this .httpsSpoofMatch = _target.getHttpsSpoofMatch();
141:                this .pageEncodings = _pageEncodings;
142:                this .formEncodings = _formEncodings;
143:            }
144:
145:            /**
146:             * Main processing method for the Proxy object
147:             */
148:            public void run() {
149:                // Check which HTTPSampler class we should use
150:                String httpSamplerName = HTTPSamplerFactory.DEFAULT_CLASSNAME;
151:                if (target.getSamplerTypeName() == ProxyControl.SAMPLER_TYPE_HTTP_SAMPLER) {
152:                    httpSamplerName = HTTPSamplerFactory.HTTP_SAMPLER_JAVA;
153:                } else if (target.getSamplerTypeName() == ProxyControl.SAMPLER_TYPE_HTTP_SAMPLER2) {
154:                    httpSamplerName = HTTPSamplerFactory.HTTP_SAMPLER_APACHE;
155:                }
156:                // Instantiate the sampler
157:                HTTPSamplerBase sampler = HTTPSamplerFactory
158:                        .newInstance(httpSamplerName);
159:
160:                HttpRequestHdr request = new HttpRequestHdr(sampler);
161:                SampleResult result = null;
162:                HeaderManager headers = null;
163:
164:                try {
165:                    request.parse(new BufferedInputStream(clientSocket
166:                            .getInputStream()));
167:
168:                    // Populate the sampler. It is the same sampler as we sent into
169:                    // the constructor of the HttpRequestHdr instance above 
170:                    request.getSampler(pageEncodings, formEncodings);
171:
172:                    /*
173:                     * Create a Header Manager to ensure that the browsers headers are
174:                     * captured and sent to the server
175:                     */
176:                    headers = request.getHeaderManager();
177:                    sampler.setHeaderManager(headers);
178:
179:                    /* 
180:                     * If we are trying to spoof https, change the protocol
181:                     */
182:                    boolean forcedHTTP = false; // so we know when to revert
183:                    if (httpsSpoof) {
184:                        if (httpsSpoofMatch.length() > 0) {
185:                            String url = request.getUrl();
186:                            if (url.matches(httpsSpoofMatch)) {
187:                                sampler
188:                                        .setProtocol(HTTPConstants.PROTOCOL_HTTPS);
189:                                forcedHTTP = true;
190:                            }
191:                        } else {
192:                            sampler.setProtocol(HTTPConstants.PROTOCOL_HTTPS);
193:                            forcedHTTP = true;
194:                        }
195:                    }
196:                    sampler.threadStarted(); // Needed for HTTPSampler2
197:                    result = sampler.sample();
198:
199:                    /*
200:                     * If we're dealing with text data, and if we're spoofing https, 
201:                     * replace all occurences of "https://" with "http://" for the client.
202:                     * TODO - also check the match string to restrict the changes further?
203:                     */
204:                    if (forcedHTTP
205:                            && SampleResult.TEXT.equals(result.getDataType())) {
206:                        final String enc = result.getDataEncodingWithDefault();
207:                        String noHttpsResult = new String(result
208:                                .getResponseData(), enc);
209:                        final String HTTPS_HOST = // match https://host[:port]/ and drop default port if present
210:                        "https://([^:/]+)(:"
211:                                + HTTPConstants.DEFAULT_HTTPS_PORT_STRING
212:                                + ")?"; // $NON-NLS-1$ $NON-NLS-2$
213:                        noHttpsResult = noHttpsResult.replaceAll(HTTPS_HOST,
214:                                "http://$1"); // $NON-NLS-1$
215:                        result.setResponseData(noHttpsResult.getBytes(enc));
216:                    }
217:
218:                    // Find the page encoding and possibly encodings for forms in the page
219:                    // in the response from the web server
220:                    String pageEncoding = addPageEncoding(result);
221:                    addFormEncodings(result, pageEncoding);
222:
223:                    writeToClient(result, new BufferedOutputStream(clientSocket
224:                            .getOutputStream()));
225:                } catch (UnknownHostException uhe) {
226:                    log.warn("Server Not Found.", uhe);
227:                    writeErrorToClient(HttpReplyHdr.formServerNotFound());
228:                    result = generateErrorResult(result, uhe); // Generate result (if nec.) and populate it
229:                } catch (IllegalArgumentException e) {
230:                    log.error("Not implemented (probably used https)", e);
231:                    writeErrorToClient(HttpReplyHdr.formNotImplemented());
232:                    result = generateErrorResult(result, e); // Generate result (if nec.) and populate it
233:                } catch (Exception e) {
234:                    log.error("Exception when processing sample", e);
235:                    writeErrorToClient(HttpReplyHdr.formTimeout());
236:                    result = generateErrorResult(result, e); // Generate result (if nec.) and populate it
237:                } finally {
238:                    if (log.isDebugEnabled()) {
239:                        log.debug("Will deliver sample " + sampler.getName());
240:                    }
241:                    /*
242:                     * We don't want to store any cookies in the generated test plan
243:                     */
244:                    if (headers != null) {
245:                        headers.removeHeaderNamed("cookie");// Always remove cookies // $NON-NLS-1$
246:                        headers.removeHeaderNamed("Authorization");// Always remove authorization // $NON-NLS-1$
247:                        // Remove additional headers
248:                        for (int i = 0; i < headersToRemove.length; i++) {
249:                            headers.removeHeaderNamed(headersToRemove[i]);
250:                        }
251:                    }
252:                    target.deliverSampler(sampler,
253:                            new TestElement[] { captureHttpHeaders ? headers
254:                                    : null }, result);
255:                    try {
256:                        clientSocket.close();
257:                    } catch (Exception e) {
258:                        log.error("", e);
259:                    }
260:                    sampler.threadFinished(); // Needed for HTTPSampler2
261:                }
262:            }
263:
264:            private SampleResult generateErrorResult(SampleResult result,
265:                    Exception e) {
266:                if (result == null) {
267:                    result = new SampleResult();
268:                    result.setSampleLabel("Sample failed");
269:                }
270:                result.setResponseMessage(e.getMessage());
271:                return result;
272:            }
273:
274:            /**
275:             * Write output to the output stream, then flush and close the stream.
276:             * 
277:             * @param inBytes
278:             *            the bytes to write
279:             * @param out
280:             *            the output stream to write to
281:             * @throws IOException
282:             *             if an IOException occurs while writing
283:             */
284:            private void writeToClient(SampleResult res, OutputStream out)
285:                    throws IOException {
286:                try {
287:                    String responseHeaders = massageResponseHeaders(res);
288:                    out.write(responseHeaders.getBytes());
289:                    out.write('\n'); // $NON-NLS-1$
290:                    out.write(res.getResponseData());
291:                    out.flush();
292:                    log.debug("Done writing to client");
293:                } catch (IOException e) {
294:                    log.error("", e);
295:                    throw e;
296:                } finally {
297:                    try {
298:                        out.close();
299:                    } catch (Exception ex) {
300:                        log.warn("Error while closing socket", ex);
301:                    }
302:                }
303:            }
304:
305:            /**
306:             * In the event the content was gzipped and unpacked, the content-encoding
307:             * header must be removed and the content-length header should be corrected.
308:             * 
309:             * The Transfer-Encoding header is also removed.
310:             * 
311:             * @param res - response
312:             * 
313:             * @return updated headers to be sent to client
314:             */
315:            private String massageResponseHeaders(SampleResult res) {
316:                String headers = res.getResponseHeaders();
317:                String[] headerLines = headers.split(NEW_LINE, 0); // drop empty trailing content
318:                int contentLengthIndex = -1;
319:                boolean fixContentLength = false;
320:                for (int i = 0; i < headerLines.length; i++) {
321:                    String line = headerLines[i];
322:                    String[] parts = line.split(":\\s+", 2); // $NON-NLS-1$
323:                    if (parts.length == 2) {
324:                        if (HTTPConstants.TRANSFER_ENCODING
325:                                .equalsIgnoreCase(parts[0])) {
326:                            headerLines[i] = null; // We don't want this passed on to browser
327:                            continue;
328:                        }
329:                        if (HTTPConstants.HEADER_CONTENT_ENCODING
330:                                .equalsIgnoreCase(parts[0])
331:                                && HTTPConstants.ENCODING_GZIP
332:                                        .equalsIgnoreCase(parts[1])) {
333:                            headerLines[i] = null; // We don't want this passed on to browser
334:                            fixContentLength = true;
335:                            continue;
336:                        }
337:                        if (HTTPConstants.HEADER_CONTENT_LENGTH
338:                                .equalsIgnoreCase(parts[0])) {
339:                            contentLengthIndex = i;
340:                            continue;
341:                        }
342:                    }
343:                }
344:                if (fixContentLength && contentLengthIndex >= 0) {// Fix the content length
345:                    headerLines[contentLengthIndex] = HTTPConstants.HEADER_CONTENT_LENGTH
346:                            + ": " + res.getResponseData().length;
347:                }
348:                StringBuffer sb = new StringBuffer(headers.length());
349:                for (int i = 0; i < headerLines.length; i++) {
350:                    String line = headerLines[i];
351:                    if (line != null) {
352:                        sb.append(line).append(NEW_LINE);
353:                    }
354:                }
355:                return sb.toString();
356:            }
357:
358:            /**
359:             * Write an error message to the client. The message should be the full HTTP
360:             * response.
361:             * 
362:             * @param message
363:             *            the message to write
364:             */
365:            private void writeErrorToClient(String message) {
366:                try {
367:                    OutputStream sockOut = clientSocket.getOutputStream();
368:                    DataOutputStream out = new DataOutputStream(sockOut);
369:                    out.writeBytes(message);
370:                    out.flush();
371:                } catch (Exception e) {
372:                    log.warn("Exception while writing error", e);
373:                }
374:            }
375:
376:            /**
377:             * Add the page encoding of the sample result to the Map with page encodings
378:             * 
379:             * @param result the sample result to check
380:             * @return the page encoding found for the sample result, or null
381:             */
382:            private String addPageEncoding(SampleResult result) {
383:                String pageEncoding = getContentEncoding(result);
384:                if (pageEncoding != null) {
385:                    String urlWithoutQuery = getUrlWithoutQuery(result.getURL());
386:                    synchronized (pageEncodings) {
387:                        pageEncodings.put(urlWithoutQuery, pageEncoding);
388:                    }
389:                }
390:                return pageEncoding;
391:            }
392:
393:            /**
394:             * Add the form encodings for all forms in the sample result
395:             * 
396:             * @param result the sample result to check
397:             * @param pageEncoding the encoding used for the sample result page
398:             */
399:            private void addFormEncodings(SampleResult result,
400:                    String pageEncoding) {
401:                FormCharSetFinder finder = new FormCharSetFinder();
402:                if (!result.getContentType().startsWith("text/")) { // TODO perhaps make more specific than this?
403:                    return; // no point parsing anything else, e.g. GIF ...
404:                }
405:                try {
406:                    finder.addFormActionsAndCharSet(result
407:                            .getResponseDataAsString(), formEncodings,
408:                            pageEncoding);
409:                } catch (HTMLParseException parseException) {
410:                    log
411:                            .debug("Unable to parse response, could not find any form character set encodings");
412:                }
413:            }
414:
415:            /**
416:             * Get the value of the charset of the content-type header of the sample result
417:             * 
418:             * @param res the sample result to find the charset for
419:             * @return the charset found, or null
420:             */
421:            private String getContentEncoding(SampleResult res) {
422:                String contentTypeHeader = res.getContentType();
423:                String charSet = null;
424:                if (contentTypeHeader != null) {
425:                    int charSetStartPos = contentTypeHeader.toLowerCase()
426:                            .indexOf("charset=");
427:                    if (charSetStartPos > 0) {
428:                        charSet = contentTypeHeader.substring(charSetStartPos
429:                                + "charset=".length());
430:                        if (charSet != null) {
431:                            if (charSet.trim().length() > 0) {
432:                                charSet = charSet.trim();
433:                            } else {
434:                                charSet = null;
435:                            }
436:                        }
437:                    }
438:                }
439:                return charSet;
440:            }
441:
442:            private String getUrlWithoutQuery(URL url) {
443:                String fullUrl = url.toString();
444:                String urlWithoutQuery = fullUrl;
445:                String query = url.getQuery();
446:                if (query != null) {
447:                    // Get rid of the query and the ?
448:                    urlWithoutQuery = urlWithoutQuery.substring(0,
449:                            urlWithoutQuery.length() - query.length() - 1);
450:                }
451:                return urlWithoutQuery;
452:            }
453:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.