+ # get header data
+ my %req_headers = %{ $self->headers || {} };
+
+ # get request_id from %content if defined for ease of use
+ if ( defined $content{"request_id"} ) {
+ $self->request_id( $content{"request_id"} );
+ }
+
+ unless ( defined( $req_headers{"X-VPS-Request-ID"} ) ) {
+ $req_headers{"X-VPS-Request-ID"} = $self->request_id();
+ }
+
+ unless ( defined( $req_headers{"X-VPS-VIT-Client-Certification-Id"} ) ) {
+ $req_headers{"X-VPS-VIT-Client-Certification-Id"} =
+ $self->client_certification_id;
+ }
+
+ unless ( defined( $req_headers{"X-VPS-Client-Timeout"} ) ) {
+ $req_headers{"X-VPS-Client-Timeout"} = $self->client_timeout();
+ }
+
+ my %options = (
+ "Content-Type" => "text/namevalue",
+ "headers" => \%req_headers,
+ );
+
+ # Payflow Pro does not use URL encoding for the request. The
+ # following implements their custom encoding scheme. Per the
+ # developer docs, the PARMLIST Syntax Guidelines are:
+ # - Spaces are allowed in values
+ # - Enclose the PARMLIST in quotation marks ("")
+ # - Do not place quotation marks ("") within the body of the PARMLIST
+ # - Separate all PARMLIST name-value pairs using an ampersand (&)
+ #
+ # Because '&' and '=' have special meanings/uses values containing
+ # these special characters must be encoded using a special "length
+ # tag". The "length tag" is simply the length of the "value"
+ # enclosed in square brackets ([]) and appended to the "name"
+ # portion of the name-value pair.
+ #
+ # For more details see the sections 'Using Special Characters in
+ # Values' and 'PARMLIST Syntax Guidelines' in the PayPal Payflow
+ # Pro Developer's Guide
+ #
+ # NOTE: we pass a string to https_post so it does not do encoding
+ my $params_string = join(
+ '&',
+ map {
+ my $key = $_;
+ my $value = defined( $params{$key} ) ? $params{$key} : '';
+ if ( index( $value, '&' ) != -1 || index( $value, '=' ) != -1 ) {
+ $key = $key . "[" . length($value) . "]";
+ }
+ "$key=$value";
+ } keys %params
+ );
+
+ my ( $page, $resp, %resp_headers ) =
+ $self->https_post( \%options, $params_string );
+
+ $self->response_code($resp);
+ $self->response_page($page);
+ $self->response_headers( \%resp_headers );
+
+ # $page should contain name=value[[&name=value]...] pairs
+ my $response = $self->_get_response( \$page );