A couple of TestMaker users asked me to add support for proxys to MaxQ so they could record tests through their corporate proxy server. I implemented proxy support for MaxQ by changing these files:

ProxyServer.java - now has a new init method to pass in the proxy name, number, and a flag determining if MaxQ should use the proxy

RequestHandler.java - if the proxy flag (set in ProxyServer's init method) is set, RequestHandler now opens the socket to the Proxy server, instead of the host

HttpRequestHeader.java - manipulates the HTTP header to send the request to the proxy

While testing this in my lab I noticed that every-other request was taking a long time (15 seconds +) to complete and close. I am going to look into this in the next day or two.

Also, the way I implemented this changes MaxQ to use HTTP 1.1 when the proxy option is enabled. This does not appear to have any effect on MaxQ working with the hosts I tested (Apache, Zope, and IIS Web servers) but this may be opening a big can of worms.

Lastly, this does not implement proxy authentication.

I'm open to any and all comments, feedback, criticism about this patch.

I am not sure what the contribution process is for MaxQ so I am just posting it here. I am willing to check it into the MaxQ cvs if needed. I would like to include this patch in the next release of TestMaker (which integrates MaxQ) so please let me know if you disagree with the patch. I'm willing to change the patch, rather than branching MaxQ.

/** * Implementation of a generic proxy server. Creates a ProxyClient for every * connection it receives. * * This is largely based on MaxQ, an open-source test utility for automatically * writing test scripts in Jython. Details at: http://maxq.tigris.org * * For more info check http://www.pushtotest.com or send email to info at pushtotest dot com * This source code is licensed under terms described in the License.txt file. * */

/** * 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;

static String CR ="\r\n";

private boolean proxyFlag = false; // If set to true, then the request is going through another proxy

/** handles the complete cycle for the communication between an http client and server * * This is largely based on MaxQ, an open-source test utility for automatically * writing test scripts in Jython. Details at: http://maxq.tigris.org * * For more info check http://www.pushtotest.com or send email to info at pushtotest dot com * This source code is licensed under terms described in the License.txt file. * */

// Open a socket to either the host or to another proxy if ( proxyServer.getProxyFlag() ) { sock = new Socket( proxyServer.getProxy(), proxyServer.getProxyNum() ); } else { sock = new Socket(InetAddress.g​etByName(url.getHost​()),port); }

/** * a request header is of this format: * Request-Line = Method SP Request-URI SP HTTP-Version CRLF * * this method assumes the second space delimited token is the request uri * and so it takes that token and strips the full url. * * this is done becuase with HTTP 1.0 the request header should contain * full URL information only if it is being sent to a proxy server, and * the proxy server is supposed to strip that information. */ private String stripProxyInfoFromRe​questHeader() {

/** * does the following <ol> * <li> get header info from client. * <li> strips all but relative address info from header * <li> sends that information to the rewritten header, along with all * the rest of the information to the server. * * <li> If the ProxyServer uses a proxy then, add the additional proxy header * info to the request and open the socket to the proxy. * * <li> gets the server response * <li> passes that information back to the client. * <li> the server should close its connection. once that happens, the * proxy closes its connection. * </ol> */ public void run() { try {