<commit_before># This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.

package Bugzilla::WebService::Server::XMLRPC;

use 5.10.1;
use strict;
use warnings;

use XMLRPC::Transport::HTTP;
use Bugzilla::WebService::Server;
if ($ENV{MOD_PERL}) {
    our @ISA = qw(XMLRPC::Transport::HTTP::Apache Bugzilla::WebService::Server);
} else {
    our @ISA = qw(XMLRPC::Transport::HTTP::CGI Bugzilla::WebService::Server);
}

use Bugzilla::WebService::Constants;
use Bugzilla::Error;
use Bugzilla::Util;

use List::MoreUtils qw(none);

BEGIN {
    # Allow WebService methods to call XMLRPC::Lite's type method directly
    *Bugzilla::WebService::type = sub {
        my ($self, $type, $value) = @_;
        if ($type eq 'dateTime') {
            # This is the XML-RPC implementation,  see the README in Bugzilla/WebService/.
            # Our "base" implementation is in Bugzilla::WebService::Server.
            $value = Bugzilla::WebService::Server->datetime_format_outbound($value);
            $value =~ s/-//g;
        }
        elsif ($type eq 'email') {
            $type = 'string';
            if (Bugzilla->params->{'webservice_email_filter'}) {
                $value = email_filter($value);
            }
        }
        return XMLRPC::Data->type($type)->value($value);
    };

    # Add support for ETags into XMLRPC WebServices
    *Bugzilla::WebService::bz_etag = sub {
        return Bugzilla::WebService::Server->bz_etag($_[1]);
    };
}

sub initialize {
    my $self = shift;
    my %retval = $self->SUPER::initialize(@_);
    $retval{'serializer'}   = Bugzilla::XMLRPC::Serializer->new;
    $retval{'deserializer'} = Bugzilla::XMLRPC::Deserializer->new;
    $retval{'dispatch_with'} = WS_DISPATCH;
    return %retval;
}

sub make_response {
    my $self = shift;
    my $cgi = Bugzilla->cgi;

    $self->SUPER::make_response(@_);

    # XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
    # its cookies in Bugzilla::CGI, so we need to copy them over.
    foreach my $cookie (@{$cgi->{'Bugzilla_cookie_list'}}) {
        $self->response->headers->push_header('Set-Cookie', $cookie);
    }

    # Copy across security related headers from Bugzilla::CGI
    foreach my $header (split(/[\r\n]+/, $cgi->header)) {
        my ($name, $value) = $header =~ /^([^:]+): (.*)/;
        if (!$self->response->headers->header($name)) {
           $self->response->headers->header($name => $value);
        }
    }

    # ETag support
    my $etag = $self->bz_etag;
    if (!$etag) {
        my $data = $self->response->as_string;
        $etag = $self->bz_etag($data);
    }

    if ($etag && $cgi->check_etag($etag)) {
        $self->response->headers->push_header('ETag', $etag);
        $self->response->headers->push_header('status', '304 Not Modified');
    }
    elsif ($etag) {
        $self->response->headers->push_header('ETag', $etag);
    }
}

sub handle_login {
    my ($self, $classes, $action, $uri, $method) = @_;
    my $class = $classes->{$uri};
    if (!$class) {
        ThrowCodeError('unknown_method', { method => $method eq 'methodName' ? '' : '.' . $method });
    }
    my $full_method = $uri . "." . $method;
    # Only allowed methods to be used from the module's whitelist
    my $file = $class;
    $file =~ s{::}{/}g;
    $file .= ".pm";
    require $file;
    if (none { $_ eq $method } $class->PUBLIC_METHODS) {
        ThrowCodeError('unknown_method', { method => $full_method });
    }
    $self->SUPER::handle_login($class, $method, $full_method);
    return;
}

1;

# This exists to validate input parameters (which XMLRPC::Lite doesn't do)
# and also, in some cases, to more-usefully decode them.
package Bugzilla::XMLRPC::Deserializer;

use 5.10.1;
use strict;
use warnings;

# We can't use "use parent" because XMLRPC::Serializer doesn't return
# a true value.
use XMLRPC::Lite;
our @ISA = qw(XMLRPC::Deserializer);

use Bugzilla::Error;
use Bugzilla::WebService::Constants qw(XMLRPC_CONTENT_TYPE_WHITELIST);
use Bugzilla::WebService::Util qw(fix_credentials);
use Scalar::Util qw(tainted);
<commit_msg>Bug 708252: The XMLRPC API doesn't work with IIS r=LpSolit<commit_after># This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.

package Bugzilla::WebService::Server::XMLRPC;

use 5.10.1;
use strict;
use warnings;

use XMLRPC::Transport::HTTP;
use Bugzilla::WebService::Server;
if ($ENV{MOD_PERL}) {
    our @ISA = qw(XMLRPC::Transport::HTTP::Apache Bugzilla::WebService::Server);
} else {
    our @ISA = qw(XMLRPC::Transport::HTTP::CGI Bugzilla::WebService::Server);
}

use Bugzilla::WebService::Constants;
use Bugzilla::Error;
use Bugzilla::Util;

use List::MoreUtils qw(none);

BEGIN {
    # Allow WebService methods to call XMLRPC::Lite's type method directly
    *Bugzilla::WebService::type = sub {
        my ($self, $type, $value) = @_;
        if ($type eq 'dateTime') {
            # This is the XML-RPC implementation,  see the README in Bugzilla/WebService/.
            # Our "base" implementation is in Bugzilla::WebService::Server.
            $value = Bugzilla::WebService::Server->datetime_format_outbound($value);
            $value =~ s/-//g;
        }
        elsif ($type eq 'email') {
            $type = 'string';
            if (Bugzilla->params->{'webservice_email_filter'}) {
                $value = email_filter($value);
            }
        }
        return XMLRPC::Data->type($type)->value($value);
    };

    # Add support for ETags into XMLRPC WebServices
    *Bugzilla::WebService::bz_etag = sub {
        return Bugzilla::WebService::Server->bz_etag($_[1]);
    };
}

sub initialize {
    my $self = shift;
    my %retval = $self->SUPER::initialize(@_);
    $retval{'serializer'}   = Bugzilla::XMLRPC::Serializer->new;
    $retval{'deserializer'} = Bugzilla::XMLRPC::Deserializer->new;
    $retval{'dispatch_with'} = WS_DISPATCH;
    return %retval;
}

sub make_response {
    my $self = shift;
    my $cgi = Bugzilla->cgi;

    # Fix various problems with IIS.
    if ($ENV{'SERVER_SOFTWARE'} =~ /IIS/) {
        $ENV{CONTENT_LENGTH} = 0;
        binmode(STDOUT, ':bytes');
    }

    $self->SUPER::make_response(@_);

    # XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
    # its cookies in Bugzilla::CGI, so we need to copy them over.
    foreach my $cookie (@{$cgi->{'Bugzilla_cookie_list'}}) {
        $self->response->headers->push_header('Set-Cookie', $cookie);
    }

    # Copy across security related headers from Bugzilla::CGI
    foreach my $header (split(/[\r\n]+/, $cgi->header)) {
        my ($name, $value) = $header =~ /^([^:]+): (.*)/;
        if (!$self->response->headers->header($name)) {
           $self->response->headers->header($name => $value);
        }
    }

    # ETag support
    my $etag = $self->bz_etag;
    if (!$etag) {
        my $data = $self->response->as_string;
        $etag = $self->bz_etag($data);
    }

    if ($etag && $cgi->check_etag($etag)) {
        $self->response->headers->push_header('ETag', $etag);
        $self->response->headers->push_header('status', '304 Not Modified');
    }
    elsif ($etag) {
        $self->response->headers->push_header('ETag', $etag);
    }
}

sub handle_login {
    my ($self, $classes, $action, $uri, $method) = @_;
    my $class = $classes->{$uri};
    if (!$class) {
        ThrowCodeError('unknown_method', { method => $method eq 'methodName' ? '' : '.' . $method });
    }
    my $full_method = $uri . "." . $method;
    # Only allowed methods to be used from the module's whitelist
    my $file = $class;
    $file =~ s{::}{/}g;
    $file .= ".pm";
    require $file;
    if (none { $_ eq $method } $class->PUBLIC_METHODS) {
        ThrowCodeError('unknown_method', { method => $full_method });
    }

    $ENV{CONTENT_LENGTH} = 0 if $ENV{'SERVER_SOFTWARE'} =~ /IIS/;
    $self->SUPER::handle_login($class, $method, $full_method);
    return;
}

1;

# This exists to validate input parameters (which XMLRPC::Lite doesn't do)
# and also, in some cases, to more-usefully decode them.
package Bugzilla::XMLRPC::Deserializer;

use 5.10.1;
use strict;
use warnings;

# We can't use "use parent" because XMLRPC::Serializer doesn't return
# a true value.
use XMLRPC::Lite;
our @ISA = qw(XMLRPC::Deserializer);

use Bugzilla::Error;
use Bugzilla::WebService::Constants qw(XMLRPC_CONTENT_TYPE_WHITELIST);
use Bugzilla::WebService::Util qw(fix_credentials);
use Scalar::Util qw(tainted);

{'fraction_non_alphanumeric': 0.16291316526610644, 'fraction_numerical': 0.00515406162464986, 'mean_word_length': 3.2769525634882606, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7571374', 'n_tokens_mistral': 3041, 'n_tokens_neox': 2887, 'n_words': 730}