####################################################################################################################################
# HTTP Common
####################################################################################################################################
package pgBackRest::Common::Http::Common;

use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';

use Exporter qw(import);
    our @EXPORT = qw();

use pgBackRest::Common::Exception;
use pgBackRest::Common::Log;

####################################################################################################################################
# httpQuery - encode an HTTP query from a hash
####################################################################################################################################
sub httpQuery
{
    # Assign function parameters, defaults, and log debug info
    my
    (
        $strOperation,
        $hQuery,
    ) =
        logDebugParam
        (
            __PACKAGE__ . '::httpQuery', \@_,
            {name => 'hQuery', required => false, trace => true},
        );

    # Generate the query string
    my $strQuery = '';

    # If a hash (the normal case)
    if (ref($hQuery))
    {
        foreach my $strParam (sort(keys(%{$hQuery})))
        {
            # Parameters may not be defined - this is OK
            if (defined($hQuery->{$strParam}))
            {
                $strQuery .= ($strQuery eq '' ? '' : '&') . $strParam . '=' . httpUriEncode($hQuery->{$strParam});
            }
        }
    }
    # Else query string was passed directly as a scalar
    elsif (defined($hQuery))
    {
        $strQuery = $hQuery;
    }

    # Return from function and log return values if any
    return logDebugReturn
    (
        $strOperation,
        {name => 'strQuery', value => $strQuery, trace => true}
    );
}

push @EXPORT, qw(httpQuery);

####################################################################################################################################
# httpUriEncode - encode query values to conform with URI specs
####################################################################################################################################
sub httpUriEncode
{
    my $strString = shift;
    my $bPath = shift;

    # Only encode if source string is defined
    my $strEncodedString;

    if (defined($strString))
    {
        # Iterate all characters in the string
        for (my $iIndex = 0; $iIndex < length($strString); $iIndex++)
        {
            my $cChar = substr($strString, $iIndex, 1);

            # These characters are reproduced verbatim
            if (($cChar ge 'A' && $cChar le 'Z') || ($cChar ge 'a' && $cChar le 'z') || ($cChar ge '0' && $cChar le '9') ||
                $cChar eq '_' || $cChar eq '-' || $cChar eq '~' || $cChar eq '.' || ($bPath && $cChar eq '/'))
            {
                $strEncodedString .= $cChar;
            }
            # Forward slash is encoded
            elsif ($cChar eq '/')
            {
                $strEncodedString .= '%2F';
            }
            # All other characters are hex-encoded
            else
            {
                $strEncodedString .= sprintf('%%%02X', ord($cChar));
            }
        }
    }

    return $strEncodedString;
}

push @EXPORT, qw(httpUriEncode);

1;
