hi,
Guys i noticed that the proxy server blocks when you try to handle a
post. I have traced the problem and manged to fix it ( source files are
attached)
Basicaly it boiled down to the post data not being collected, and posted
to the destination server correctly.
what i have basicaly done is to get the output stream from
HttpURLConnection in Proxy.java and write to it. The data has to be
collected at the request.parse method. Some how it does not seem to work
in the run method in Proxy.java So i have had to add
public String postData = new String();
to HttpRequestHdr.java
hope i haven't broken something else in the process.
Appreciate the good work that you guys are doing.
Raditha Dissanayake.
package org.apache.jmeter.protocol.http.proxy;
/******************************************************************
*** File HttpRequestHdr.java
***
***/
import java.io.InputStream;
import java.io.DataInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
//
// Class: HttpRequestHdr
// Abstract: The headers of the client HTTP request.
//
public class HttpRequestHdr
{
/**
* Http Request method. Such as get or post.
*/
public String method = new String();
/**
* The requested url. The universal resource locator that
* hopefully uniquely describes the object or service the
* client is requesting.
*/
public String url = new String();
/**
* Version of http being used. Such as HTTP/1.0
*/
public String version = new String();
/**
* The client's browser's name.
*/
public String userAgent = new String();
/**
* The requesting documents that contained the url link.
*/
public String referer = new String();
/**
* A internet address date of the remote copy.
*/
public String ifModifiedSince = new String();
/**
* A list of mime types the client can accept.
*/
public String accept = new String();
/**
* The clients authorization. Don't belive it.
*/
public String authorization = new String();
/**
* The type of content following the request header.
* Normally there is no content and this is blank, however
* the post method usually does have a content and a content
* length.
*/
public String contentType = new String();
/**
* The length of the content following the header. Usually
* blank.
*/
public int contentLength = -1;
/**
* The content length of a remote copy of the requested object.
*/
public int oldContentLength = -1;
/**
* Anything in the header that was unrecognized by this class.
*/
public String unrecognized = new String();
/**
* Indicates that no cached versions of the requested object are
* to be sent. Usually used to tell proxy not to send a cached copy.
* This may also effect servers that are front end for data bases.
*/
public boolean pragmaNoCache = false;
public String postData = new String();
static String CR ="\r\n";
/**
* Parses a http header from a stream.
*
* @param in The stream to parse.
* @return true if parsing sucsessfull.
*/
public boolean parse(InputStream In)
{
String CR ="\r\n";
/*
* Read by lines
*/
BufferedReader lines;
StringTokenizer tz;
try
{
lines = new BufferedReader(new InputStreamReader(new
DataInputStream(In)));
tz = new StringTokenizer(lines.readLine());
}
catch (Exception e)
{
return false;
}
/*
* HTTP COMMAND LINE < <METHOD==get> <URL> <HTTP_VERSION> >
*/
method = getToken(tz).toUpperCase();
url = getToken(tz);
version= getToken(tz);
while (true)
{
try
{
tz = new StringTokenizer(lines.readLine());
}
catch (Exception e)
{
return false;
}
String Token = getToken(tz);
// look for termination of HTTP command
if (0 == Token.length())
{
if(method.equals("POST"))
{
try
{
postData = lines.readLine();
}
catch (Exception e)
{
System.out.println("fucked up trying to read
post data");
break;
}
}
break;
}
if (Token.equalsIgnoreCase("USER-AGENT:")) {
// line =<User-Agent: <Agent Description>>
userAgent = getRemainder(tz);
} else if (Token.equalsIgnoreCase("ACCEPT:")) {
// line=<Accept: <Type>/<Form>
// examp: Accept image/jpeg
accept += " " + getRemainder(tz);
} else if (Token.equalsIgnoreCase("REFERER:")) {
// line =<Referer: <URL>>
referer = getRemainder(tz);
} else if (Token.equalsIgnoreCase("PRAGMA:")) {
// Pragma: <no-cache>
Token = getToken(tz);
if (Token.equalsIgnoreCase("NO-CACHE"))
pragmaNoCache = true;
else
unrecognized += "Pragma:" + Token + " "
+getRemainder(tz) +"\n";
} else if (Token.equalsIgnoreCase("AUTHORIZATION:")) {
// Authenticate: Basic UUENCODED
authorization= getRemainder(tz);
} else if (Token.equalsIgnoreCase("IF-MODIFIED-SINCE:")) {
// line =<If-Modified-Since: <http date>
// *** Conditional GET replaces HEAD method ***
String str = getRemainder(tz);
int index = str.indexOf(";");
if (index == -1) {
ifModifiedSince =str;
} else {
ifModifiedSince =str.substring(0,index);
index = str.indexOf("=");
if (index != -1) {
str = str.substring(index+1);
oldContentLength =Integer.parseInt(str);
}
}
} else if (Token.equalsIgnoreCase("CONTENT-LENGTH:")) {
Token = getToken(tz);
contentLength =Integer.parseInt(Token);
} else if (Token.equalsIgnoreCase("CONTENT-TYPE:")) {
contentType = getRemainder(tz);
} else {
unrecognized += Token + " " + getRemainder(tz) + CR;
}
}
return true;
}
/*
* Rebuilds the header in a string
* @returns The header in a string.
*/
public String toString(boolean sendUnknowen) {
String Request;
if (0 == method.length())
method = "GET";
Request = method +" "+ url + " HTTP/1.0" + CR;
if (0 < userAgent.length())
Request +="User-Agent:" + userAgent + CR;
if (0 < referer.length())
Request+= "Referer:"+ referer + CR;
if (pragmaNoCache)
Request+= "Pragma: no-cache" + CR;
if (0 < ifModifiedSince.length())
Request+= "If-Modified-Since: " + ifModifiedSince + CR;
// ACCEPT TYPES //
if (0 < accept.length())
Request += "Accept: " + accept + CR;
else
Request += "Accept: */"+"* \r\n";
if (0 < contentType.length())
Request += "Content-Type: " + contentType + CR;
if (0 < contentLength)
Request += "Content-Length: " + contentLength + CR;
if (0 != authorization.length())
Request += "Authorization: " + authorization + CR;
if (sendUnknowen) {
if (0 != unrecognized.length())
Request += unrecognized;
}
Request += CR;
return Request;
}
/**
* (Re)builds the header in a string.
*
* @returns The header in a string.
*/
public String toString() {
return toString(true);
}
/**
* Returns the next token in a string
*
* @param tk String that is partially tokenized.
* @returns The remainder
*/
String getToken(StringTokenizer tk){
String str ="";
if (tk.hasMoreTokens())
str =tk.nextToken();
return str;
}
/**
* Returns the remainder of a tokenized string
*
* @param tk String that is partially tokenized.
* @returns The remainder
*/
String getRemainder(StringTokenizer tk){
String str ="";
if (tk.hasMoreTokens())
str =tk.nextToken();
while (tk.hasMoreTokens()){
str +=" " + tk.nextToken();
}
return str;
}
//
// Parsing Methods
//
/**
* Find the //server.name from an url.
*
* @return Servers internet name
*/
public String serverName()
{
// chop to "server.name:x/thing"
String str = url;
int i = str.indexOf("//");
if (i< 0) return "";
str = str.substring(i+2);
// chop to server.name:xx
i = str.indexOf("/");
if (0 < i) str = str.substring(0,i);
// chop to server.name
i = str.indexOf(":");
if (0 < i) str = str.substring(0,i);
return str;
}
/**
* Find the :PORT form http://server.ect:PORT/some/file.xxx
*
* @return Servers internet name
*/
public int serverPort()
{
String str = url;
// chop to "server.name:x/thing"
int i = str.indexOf("//");
if (i< 0) return 80;
str = str.substring(i+2);
// chop to server.name:xx
i = str.indexOf("/");
if (0 < i) str = str.substring(0,i);
// chop XX
i = str.indexOf(":");
if (0 < i)
{
return Integer.parseInt(str.substring(i+1).trim());
}
return 80;
}
/**
* Find the /some/file.xxxx form http://server.ect:PORT/some/file.xxx
*
* @return the deproxied url
*/
public String serverUrl()
{
String str = url;
int i = str.indexOf("//");
if (i< 0) return str;
str = str.substring(i+2);
i = str.indexOf("/");
if (i< 0) return str;
return str.substring(i);
}
}
/*
* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache JMeter" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* "Apache JMeter", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.jmeter.protocol.http.proxy;
import java.net.*;
import java.io.*;
import java.util.*;
import org.apache.jmeter.protocol.http.config.UrlConfig;
import org.apache.jmeter.save.xml.TagHandler;
//
// Class: Proxy
// Abstract: Thread to handle one client request. get the requested
// object from the web server or from the cache, and delivers
// the bits to client.
//
/**
* Description of the Class
*
*@author mike
*@created June 8, 2001
*/
public class Proxy extends Thread
{
//
// Member variables
//
Socket ClientSocket = null;
// Socket to client
Socket SrvrSocket = null;
// Socket to web server
Cache cache = null;
// Static cache manager object
String localHostName = null;
// Local machine name
String localHostIP = null;
// Local machine IP address
String adminPath = null;
// Path of admin applet
Config config = null;
// Config object
UrlConfig urlConfig = null;
// UrlConfig object for saving test cases
ProxyControl target;
//
// Public member methods
//
//
// Constructor
//
Proxy(Socket clientSocket, Cache CacheManager, Config
configObject,ProxyControl target)
{
//
// Initialize member variables
//
this.target = target;
config = configObject;
ClientSocket = clientSocket;
cache = CacheManager;
localHostName = config.getLocalHost();
localHostIP = config.getLocalIP();
adminPath = config.getAdminPath();
}
//
// run - Main work is done here:
//
/**
* Main processing method for the Proxy object
*/
public void run()
{
String serverName = "";
URL url;
byte line[];
HttpRequestHdr request = new HttpRequestHdr();
HttpReplyHdr reply = new HttpReplyHdr();
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
boolean TakenFromCache = false;
boolean isCachable = false;
try
{
//
// Read HTTP Request from client
//
request.parse(ClientSocket.getInputStream());
createUrlConfig(request);
config.increaseFilesCached();
url = new URL(request.url);
System.out.println("Request = " + url);
//
// Send Web page with applet to administrator
//
if (url.getFile().equalsIgnoreCase("/admin") &&
(url.getHost().equalsIgnoreCase(localHostName)
||
url.getHost().equalsIgnoreCase(localHostIP)))
{
sendAppletWebPage();
return;
}
//
// Send Applet Files to administrator
//
if ((url.getHost().equalsIgnoreCase(localHostName) ||
url.getHost().equalsIgnoreCase(localHostIP)))
{
sendAppletClass(url.getFile());
return;
}
//
// Check if accessing the URL is allowed by administrator
//
String[] denied = config.getDeniedHosts();
for (int i = 0; i < denied.length; i++)
{
if (url.toString().indexOf(denied[i]) != -1)
{
System.out.println("Access not allowed...");
DataOutputStream out =
new
DataOutputStream(ClientSocket.getOutputStream());
out.writeBytes(reply.formNotAllowed());
out.flush();
ClientSocket.close();
return;
}
}
serverName = url.getHost();
System.out.println("Miss! Forwarding to server " +
serverName + "...");
config.increaseMisses();
HttpURLConnection conn =
(HttpURLConnection)url.openConnection();
/*
//
// Send data to server (needed for post method)
//
StringBuffer buff = new StringBuffer();
int readValue;
for (int i = 0; i < request.contentLength; i++)
{
readValue = ClientSocket.getInputStream().read();
buff.append((char)readValue);
}
*/
if(request.method.equals("POST"))
{
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-length",String.valueOf(request.contentLength));
conn.connect();
//nn.setRequestProperty("Content-length",reques);
urlConfig.parseArguments(request.postData);
OutputStream postOut = conn.getOutputStream();
postOut.write(request.postData.getBytes(), 0,
request.contentLength);
System.out.println("post data: " + request.postData);
}
else
{
conn.connect();
}
target.deliverUrlConfig(urlConfig);
OutputStream out = ClientSocket.getOutputStream();
byte[] buffer = new byte[4096];
BufferedInputStream in = new
BufferedInputStream(conn.getInputStream());
int x = 0;
while ((x = in.read(buffer)) != -1)
{
out.write(buffer, 0, x);
}
in.close();
out.flush();
}
catch (UnknownHostException uhe)
{
//
// Requested Server could not be located
//
System.out.println("Server Not Found.");
try
{
// Notify client that server not found
DataOutputStream out =
new
DataOutputStream(ClientSocket.getOutputStream());
out.writeBytes(reply.formServerNotFound());
out.flush();
}
catch (Exception uhe2)
{
}
}
catch (Exception e)
{
e.printStackTrace();
try
{
if (TakenFromCache)
{
fileInputStream.close();
}
else if (isCachable)
{
fileOutputStream.close();
}
// Notify client that internal error accured in proxy
DataOutputStream out =
new
DataOutputStream(ClientSocket.getOutputStream());
out.writeBytes(reply.formTimeout());
out.flush();
}
catch (Exception uhe2)
{
}
}
finally
{
try
{
ClientSocket.getOutputStream().flush();
ClientSocket.close();
}
catch (Exception e)
{
}
}
}
//
// Private methods
//
//
// Send to administrator web page containing reference to applet
//
private void sendAppletWebPage()
{
System.out.println("Sending the applet...");
String page = "";
try
{
File appletHtmlPage = new File(config.getAdminPath() +
File.separator + "Admin.html");
BufferedReader in = new BufferedReader(new
InputStreamReader(new FileInputStream(appletHtmlPage)));
String s = null;
while ((s = in.readLine()) != null)
{
page += s;
}
page = page.substring(0, page.indexOf("PORT")) +
config.getAdminPort() +
page.substring(page.indexOf("PORT") + 4);
in.close();
DataOutputStream out = new
DataOutputStream(ClientSocket.getOutputStream());
out.writeBytes(page);
out.flush();
out.close();
}
catch (Exception e)
{
System.out.println("Error: can't open applet html page");
}
}
//
// Send the applet to administrator
//
private void sendAppletClass(String className)
{
try
{
byte data[] = new byte[2000];
int count;
HttpReplyHdr reply = new HttpReplyHdr();
File appletFile = new File(adminPath + File.separatorChar +
className);
long length = appletFile.length();
FileInputStream in = new FileInputStream(appletFile);
DataOutputStream out = new
DataOutputStream(ClientSocket.getOutputStream());
out.writeBytes(reply.formOk("application/octet-stream",
length));
while (-1 < (count = in.read(data)))
{
out.write(data, 0, count);
}
out.flush();
in.close();
out.close();
}
catch (Exception e)
{
}
}
private void createUrlConfig(HttpRequestHdr request)
{
System.out.println("Everything = " + request.toString(true));
urlConfig = UrlConfig.createConfig(request.contentType);
urlConfig.setDomain(request.serverName());
urlConfig.setMethod(request.method);
urlConfig.setPath(request.serverUrl());
urlConfig.setName(urlConfig.getPath());
urlConfig.setProtocol(request.url.substring(0,
request.url.indexOf(":")));
urlConfig.setPort(request.serverPort());
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>