Skip to content
Merged
26 changes: 26 additions & 0 deletions models/CfhttpHttpClient.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ component implements="HyperHttpClientInterface" {
attrCollection[ "clientCertPassword" ] = req.getClientCertPassword();
}

if ( len( req.getProxyServer() ) ) {
attrCollection[ "proxyServer" ] = req.getProxyServer();
attrCollection[ "proxyPort" ] = req.getProxyPort();

if ( len( req.getProxyUser() ) ) {
attrCollection[ "proxyUser" ] = req.getProxyUser();
}

if ( len( req.getProxyPassword() ) ) {
attrCollection[ "proxyPassword" ] = req.getProxyPassword();
}
}

var cfhttpHeaders = [];
var headers = req.getHeaders();
for ( var name in headers ) {
Expand Down Expand Up @@ -235,6 +248,19 @@ component implements="HyperHttpClientInterface" {
attrCollection[ "clientCertPassword" ] = req.getClientCertPassword();
}

if ( len( req.getProxyServer() ) ) {
attrCollection[ "proxyServer" ] = req.getProxyServer();
attrCollection[ "proxyPort" ] = req.getProxyPort();

if ( len( req.getProxyUser() ) ) {
attrCollection[ "proxyUser" ] = req.getProxyUser();
}

if ( len( req.getProxyPassword() ) ) {
attrCollection[ "proxyPassword" ] = req.getProxyPassword();
}
}

cfhttp( attributeCollection = attrCollection ) {
var headers = req.getHeaders();
for ( var name in headers ) {
Expand Down
102 changes: 79 additions & 23 deletions models/HyperRequest.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,26 @@ component accessors="true" {
*/
property name="preventStrayRequests" type="boolean";

/**
* The proxy server for the request.
*/
property name="proxyServer" default="";

/**
* The proxy port for the request.
*/
property name="proxyPort" default="80";

/**
* The proxy user for the request.
*/
property name="proxyUser" default="";

/**
* The proxy password for the request.
*/
property name="proxyPassword" default="";

/**
* A reference to the HyperBuilder that created this request, if any.
*/
Expand Down Expand Up @@ -840,6 +860,29 @@ component accessors="true" {
return this;
}

/**
* Sets the proxy settings for the request.
*
* @proxyHost The proxy server host or IP address.
* @proxyPort The proxy server port. Defaults to 80.
* @proxyUser The username for proxy authentication. Defaults to empty string.
* @proxyPassword The password for proxy authentication. Defaults to empty string.
*
* @returns The HyperRequest instance.
*/
function throughProxy(
required string proxyHost,
numeric proxyPort = 80,
string proxyUser = "",
string proxyPassword = ""
) {
setProxyServer( arguments.proxyHost );
setProxyPort( arguments.proxyPort );
setProxyUser( arguments.proxyUser );
setProxyPassword( arguments.proxyPassword );
return this;
}

/**
* Schedules a callback to be ran when executing the request.
*
Expand Down Expand Up @@ -1110,7 +1153,10 @@ component accessors="true" {
callback( res );
}

param variables.useAnnounceMethodForInterceptorService = structKeyExists( variables.interceptorService, "announce" );
param variables.useAnnounceMethodForInterceptorService = structKeyExists(
variables.interceptorService,
"announce"
);
if ( variables.useAnnounceMethodForInterceptorService ) {
variables.interceptorService.announce(
"onHyperResponse",
Expand Down Expand Up @@ -1311,6 +1357,10 @@ component accessors="true" {
req.setDomain( variables.domain );
req.setWorkstation( variables.workstation );
req.setAuthType( variables.authType );
req.setProxyServer( variables.proxyServer );
req.setProxyPort( variables.proxyPort );
req.setProxyUser( variables.proxyUser );
req.setProxyPassword( variables.proxyPassword );
req.setRequestCallbacks( duplicate( variables.requestCallbacks ) );
req.setResponseCallbacks( duplicate( variables.responseCallbacks ) );
req.setRetries( duplicate( getRetries() ) );
Expand Down Expand Up @@ -1429,28 +1479,34 @@ component accessors="true" {
public struct function getMemento( array excludes = [] ) {
return structFilter(
{
"requestID" : getRequestID(),
"baseUrl" : getBaseUrl(),
"url" : getUrl(),
"fullUrl" : getFullUrl(),
"method" : getMethod(),
"queryParams" : getQueryParams(),
"headers" : getHeaders(),
"cookies" : getCookies(),
"files" : getFiles(),
"bodyFormat" : getBodyFormat(),
"body" : getBody(),
"referrerId" : isNull( variables.referrer ) ? "" : variables.referrer.getResponseID(),
"throwOnError" : getThrowOnError(),
"timeout" : getTimeout(),
"maximumRedirects" : getMaximumRedirects(),
"authType" : getAuthType(),
"username" : getUsername(),
"password" : getPassword(),
"clientCert" : isNull( variables.clientCert ) ? "" : variables.clientCert,
"clientCertPassword" : isNull( variables.clientCertPassword ) ? "" : variables.clientCertPassword,
"domain" : getDomain(),
"workstation" : getWorkstation(),
"requestID" : getRequestID(),
"baseUrl" : getBaseUrl(),
"url" : getUrl(),
"fullUrl" : getFullUrl(),
"method" : getMethod(),
"queryParams" : getQueryParams(),
"headers" : getHeaders(),
"cookies" : getCookies(),
"files" : getFiles(),
"bodyFormat" : getBodyFormat(),
"body" : getBody(),
"referrerId" : isNull( variables.referrer ) ? "" : variables.referrer.getResponseID(),
"throwOnError" : getThrowOnError(),
"timeout" : getTimeout(),
"maximumRedirects" : getMaximumRedirects(),
"authType" : getAuthType(),
"username" : getUsername(),
"password" : getPassword(),
"clientCert" : isNull( variables.clientCert ) ? "" : variables.clientCert,
"clientCertPassword" : isNull( variables.clientCertPassword ) ? "" : variables.clientCertPassword,
"domain" : getDomain(),
"workstation" : getWorkstation(),
"proxy" : {
"proxyServer" : getProxyServer(),
"proxyPort" : getProxyPort(),
"proxyUser" : getProxyUser(),
"proxyPassword" : getProxyPassword()
},
"resolveUrls" : getResolveUrls(),
"encodeUrl" : getEncodeUrl(),
"retries" : getRetries(),
Expand Down
24 changes: 24 additions & 0 deletions tests/specs/integration/DebugSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,30 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
expect( headers[ 4 ] ).toHaveKey( "value" );
expect( headers[ 4 ].value ).toBe( "HyperCFML/#req.getHyperVersion()#" );
} );

it( "includes proxy settings in debug output", function() {
var req = hyper
.setUrl( "https://example.com" )
.throughProxy(
proxyHost = "proxy.example.com",
proxyUser = "proxyuser",
proxyPassword = "proxypass",
proxyPort = 8080
);

var debugReq = req.debug();

expect( debugReq ).toBeStruct();
expect( debugReq ).toHaveKey( "attributes" );
expect( debugReq.attributes ).toHaveKey( "proxyServer" );
expect( debugReq.attributes.proxyServer ).toBe( "proxy.example.com" );
expect( debugReq.attributes ).toHaveKey( "proxyPort" );
expect( debugReq.attributes.proxyPort ).toBe( 8080 );
expect( debugReq.attributes ).toHaveKey( "proxyUser" );
expect( debugReq.attributes.proxyUser ).toBe( "proxyuser" );
expect( debugReq.attributes ).toHaveKey( "proxyPassword" );
expect( debugReq.attributes.proxyPassword ).toBe( "proxypass" );
} );
} );
}

Expand Down
127 changes: 105 additions & 22 deletions tests/specs/unit/HyperRequestSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,34 @@ component extends="testbox.system.BaseSpec" {

it( "can serialize to a memento", function() {
expect( variables.req.getMemento() ).toBe( {
"requestID" : variables.req.getRequestID(),
"baseUrl" : variables.req.getBaseUrl(),
"url" : variables.req.getUrl(),
"fullUrl" : variables.req.getFullUrl(),
"method" : variables.req.getMethod(),
"queryParams" : variables.req.getQueryParams(),
"headers" : variables.req.getHeaders(),
"cookies" : variables.req.getCookies(),
"files" : variables.req.getFiles(),
"bodyFormat" : variables.req.getBodyFormat(),
"body" : variables.req.getBody(),
"referrerId" : "",
"throwOnError" : variables.req.getThrowOnError(),
"timeout" : variables.req.getTimeout(),
"maximumRedirects" : variables.req.getMaximumRedirects(),
"authType" : variables.req.getAuthType(),
"username" : variables.req.getUsername(),
"password" : variables.req.getPassword(),
"clientCert" : "",
"clientCertPassword" : "",
"domain" : variables.req.getDomain(),
"workstation" : variables.req.getWorkstation(),
"requestID" : variables.req.getRequestID(),
"baseUrl" : variables.req.getBaseUrl(),
"url" : variables.req.getUrl(),
"fullUrl" : variables.req.getFullUrl(),
"method" : variables.req.getMethod(),
"queryParams" : variables.req.getQueryParams(),
"headers" : variables.req.getHeaders(),
"cookies" : variables.req.getCookies(),
"files" : variables.req.getFiles(),
"bodyFormat" : variables.req.getBodyFormat(),
"body" : variables.req.getBody(),
"referrerId" : "",
"throwOnError" : variables.req.getThrowOnError(),
"timeout" : variables.req.getTimeout(),
"maximumRedirects" : variables.req.getMaximumRedirects(),
"authType" : variables.req.getAuthType(),
"username" : variables.req.getUsername(),
"password" : variables.req.getPassword(),
"clientCert" : "",
"clientCertPassword" : "",
"domain" : variables.req.getDomain(),
"workstation" : variables.req.getWorkstation(),
"proxy" : {
"proxyServer" : variables.req.getProxyServer(),
"proxyPort" : variables.req.getProxyPort(),
"proxyUser" : variables.req.getProxyUser(),
"proxyPassword" : variables.req.getProxyPassword()
},
"resolveUrls" : variables.req.getResolveUrls(),
"encodeUrl" : variables.req.getEncodeUrl(),
"retries" : variables.req.getRetries(),
Expand Down Expand Up @@ -166,6 +172,83 @@ component extends="testbox.system.BaseSpec" {
expect( req.getClientCertPassword() ).toBe( "mypassword" );
} );

it( "can set proxy settings via throughProxy method", function() {
expect( req.getProxyServer() ).toBe( "" );
expect( req.getProxyPort() ).toBe( 80 );
expect( req.getProxyUser() ).toBe( "" );
expect( req.getProxyPassword() ).toBe( "" );
req.throughProxy(
proxyHost = "proxy.example.com",
proxyUser = "proxyuser",
proxyPassword = "proxypass",
proxyPort = 8080
);
expect( req.getProxyServer() ).toBe( "proxy.example.com" );
expect( req.getProxyPort() ).toBe( 8080 );
expect( req.getProxyUser() ).toBe( "proxyuser" );
expect( req.getProxyPassword() ).toBe( "proxypass" );
} );

it( "can set proxy settings with default port", function() {
expect( req.getProxyPort() ).toBe( 80 );
req.throughProxy(
proxyHost = "proxy.example.com",
proxyUser = "proxyuser",
proxyPassword = "proxypass"
);
expect( req.getProxyServer() ).toBe( "proxy.example.com" );
expect( req.getProxyPort() ).toBe( 80 );
expect( req.getProxyUser() ).toBe( "proxyuser" );
expect( req.getProxyPassword() ).toBe( "proxypass" );
} );

it( "can set proxy settings without authentication", function() {
req.throughProxy( proxyHost = "proxy.example.com" );
expect( req.getProxyServer() ).toBe( "proxy.example.com" );
expect( req.getProxyPort() ).toBe( 80 );
expect( req.getProxyUser() ).toBe( "" );
expect( req.getProxyPassword() ).toBe( "" );
} );

it( "can set proxy settings with custom port but no authentication", function() {
req.throughProxy( proxyHost = "proxy.example.com", proxyPort = 8080 );
expect( req.getProxyServer() ).toBe( "proxy.example.com" );
expect( req.getProxyPort() ).toBe( 8080 );
expect( req.getProxyUser() ).toBe( "" );
expect( req.getProxyPassword() ).toBe( "" );
} );

it( "includes proxy settings in memento", function() {
req.throughProxy(
proxyHost = "proxy.example.com",
proxyUser = "proxyuser",
proxyPassword = "proxypass",
proxyPort = 8080
);
var memento = req.getMemento();
expect( memento ).toHaveKey( "proxy" );
expect( memento.proxy ).toBe( {
"proxyServer" : "proxy.example.com",
"proxyPort" : 8080,
"proxyUser" : "proxyuser",
"proxyPassword" : "proxypass"
} );
} );

it( "clones proxy settings to new request", function() {
req.throughProxy(
proxyHost = "proxy.example.com",
proxyUser = "proxyuser",
proxyPassword = "proxypass",
proxyPort = 8080
);
var clonedReq = req.clone();
expect( clonedReq.getProxyServer() ).toBe( "proxy.example.com" );
expect( clonedReq.getProxyPort() ).toBe( 8080 );
expect( clonedReq.getProxyUser() ).toBe( "proxyuser" );
expect( clonedReq.getProxyPassword() ).toBe( "proxypass" );
} );

it( "can define onRequest callback hooks", function() {
var method = "not set yet";
var headers = {};
Expand Down