package Plack::Middleware::TrafficAdvice;

# ABSTRACT: handle requests for /.well-known/traffic-advice

use v5.12;
use warnings;

use parent 'Plack::Middleware';

use Plack::Util::Accessor qw/ data file /;

use Cwd;
use File::Temp qw/ tempfile /;
use HTTP::Date;
use HTTP::Status qw/ :constants /;
use JSON::MaybeXS 1.004000;

our $VERSION = 'v0.3.1';


sub prepare_app {
    my ($self) = @_;

    if (my $data = $self->data) {

        if ($self->file) {
            die "Cannot specify both data and file";
        }

        my ($fh, $filename) = tempfile('traffic-advice-XXXXXXXX', SUFFIX => '.json', UNLINK => 0, TMPDIR => 1);
        $self->file( $filename );

        if (ref($data)) {
            my $encoder = JSON::MaybeXS->new( { utf8 => 1 } );
            print {$fh} $encoder->encode($data)
                or die "Unable to write data";
        }
        else {
            print {$fh} $data
                or die "Unable to write data";
        }

        close $fh;


    }
    elsif (my $file = $self->file) {

        unless (-r $file) {
            die "Cannot read file: '$file'";
        }

    }
    else {
        die "Either data or file must be configured";
    }

}

sub call {
    my ( $self, $env ) = @_;

    unless ( $env->{REQUEST_URI} eq '/.well-known/traffic-advice' ) {
        return $self->app->($env);
    }

    unless ( $env->{REQUEST_METHOD} =~ /^(GET|HEAD)$/ ) {
        return $self->error( HTTP_METHOD_NOT_ALLOWED, "Not Allowed" );
    }

    my $file = $self->file;

    # Some of this is based on Plack::App::File.

    open my $fh, "<:raw", $file
        or return $self->error( HTTP_INTERNAL_SERVER_ERROR, "Internal Error" );

    my @stat = stat $file;

    Plack::Util::set_io_path($fh, Cwd::realpath($file));

    [
        HTTP_OK,
        [
         'Content-Type'   => 'application/trafficadvice+json',
         'Content-Length' => $stat[7],
         'Last-Modified'  => HTTP::Date::time2str( $stat[9] )
        ],
        $fh,
    ];

}


sub error {
    my ($self, $code, $message) = @_;
    return [ $code, [ 'Content-Type' => 'text/plain', 'Content-Length' => length($message) ], [ $message ] ];
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Plack::Middleware::TrafficAdvice - handle requests for /.well-known/traffic-advice

=head1 VERSION

version v0.3.1

=head1 SYNOPSIS

  use JSON::MaybeXS 1.004000;
  use Plack::Builder;

  builder {

    enable "TrafficAdvice",
      data => [
        {
            user_agent => "prefetch-proxy",
            disallow   => JSON::MaybeXS->true,
        }
      ];

    ...

  };

=head1 DESCRIPTION

This middle provides a handler for requests for C</.well-known/traffic-advice>.

You must specify either a L</file> or L</data> containing the traffic
advice information. (There is no default value.)

=head1 ATTRIBUTES

=head2 data

This is either an array referece that corresponds to the traffic advice data structure,
or a JSON string to return.

The data will be saved as a temporary L</file>.

=head2 file

This is a file containing the JSON string to return.

=for Pod::Coverage error

=head1 KNOWN ISSUES

The C</.well-known/traffic-advice> specification is new and may be subject to change.

This does not validate that the L</data> string or L</file> contains
valid JSON, or that the JSON conforms to the specification.

=head1 SUPPORT FOR OLDER PERL VERSIONS

This module requires Perl v5.12 or later.

Future releases may only support Perl versions released in the last ten (10) years.

=head1 SEE ALSO

L<https://github.com/buettner/private-prefetch-proxy/blob/main/traffic-advice.md>

=head1 SOURCE

The development version is on github at L<https://github.com/robrwo/Plack-Middleware-TrafficAdvice>
and may be cloned from L<git://github.com/robrwo/Plack-Middleware-TrafficAdvice.git>

=head1 BUGS

Please report any bugs or feature requests on the bugtracker website
L<https://github.com/robrwo/Plack-Middleware-TrafficAdvice/issues>

When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.

=head2 Reporting Security Vulnerabilities

Security issues should not be reported on the bugtracker website. Please see F<SECURITY.md> for instructions how to
report security vulnerabilities

=head1 AUTHOR

Robert Rothenberg <rrwo@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2021-2024 by Robert Rothenberg.

This is free software, licensed under:

  The Artistic License 2.0 (GPL Compatible)

=cut
