From bcbb20f3a175dd76110c6851e67ebf8f559bb22e Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jul 23 2021 08:30:19 +0000 Subject: import perl-HTTP-Daemon-6.01-23.el8 --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..539b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/HTTP-Daemon-6.01.tar.gz diff --git a/.perl-HTTP-Daemon.metadata b/.perl-HTTP-Daemon.metadata new file mode 100644 index 0000000..a86fdd5 --- /dev/null +++ b/.perl-HTTP-Daemon.metadata @@ -0,0 +1 @@ +d3b7614d4b3be4b61d26011efe90026c955102a4 SOURCES/HTTP-Daemon-6.01.tar.gz diff --git a/SOURCES/HTTP-Daemon-6.01-Add-IPv6-support.patch b/SOURCES/HTTP-Daemon-6.01-Add-IPv6-support.patch new file mode 100644 index 0000000..dd9d5ee --- /dev/null +++ b/SOURCES/HTTP-Daemon-6.01-Add-IPv6-support.patch @@ -0,0 +1,305 @@ +From 067faffb8e596a53c9ac2ed7e571472f7a163681 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= +Date: Mon, 16 Jan 2017 16:13:08 +0100 +Subject: [PATCH] Add IPv6 support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch ports the code from IO::Socket::INET to IO::Socket::IP in +order to support IPv6. + +CPAN RT #91699, #71395. + +Signed-off-by: Petr Písař +--- + Makefile.PL | 1 + + README | 24 ++++++++++++------------ + lib/HTTP/Daemon.pm | 43 ++++++++++++++++++++++++++++--------------- + t/chunked.t | 34 +++++++++++++++++++++++----------- + 4 files changed, 64 insertions(+), 38 deletions(-) + +diff --git a/Makefile.PL b/Makefile.PL +index 09c7e86..85d5712 100644 +--- a/Makefile.PL ++++ b/Makefile.PL +@@ -14,6 +14,7 @@ WriteMakefile( + PREREQ_PM => { + 'Sys::Hostname' => 0, + 'IO::Socket' => 0, ++ 'IO::Socket::IP' => 0, + 'HTTP::Request' => 6, + 'HTTP::Response' => 6, + 'HTTP::Status' => 6, +diff --git a/README b/README +index be5a20a..ddb3b6e 100644 +--- a/README ++++ b/README +@@ -24,12 +24,12 @@ SYNOPSIS + DESCRIPTION + Instances of the `HTTP::Daemon' class are HTTP/1.1 servers that listen + on a socket for incoming requests. The `HTTP::Daemon' is a subclass of +- `IO::Socket::INET', so you can perform socket operations directly on it ++ `IO::Socket::IP', so you can perform socket operations directly on it + too. + + The accept() method will return when a connection from a client is + available. The returned value will be an `HTTP::Daemon::ClientConn' +- object which is another `IO::Socket::INET' subclass. Calling the ++ object which is another `IO::Socket::IP' subclass. Calling the + get_request() method on this object will read data from the client and + return an `HTTP::Request' object. The ClientConn object also provide + methods to send back various responses. +@@ -40,13 +40,13 @@ DESCRIPTION + responses that conform to the HTTP/1.1 protocol. + + The following methods of `HTTP::Daemon' are new (or enhanced) relative +- to the `IO::Socket::INET' base class: ++ to the `IO::Socket::IP' base class: + + $d = HTTP::Daemon->new + $d = HTTP::Daemon->new( %opts ) + The constructor method takes the same arguments as the +- `IO::Socket::INET' constructor, but unlike its base class it can +- also be called without any arguments. The daemon will then set up a ++ `IO::Socket::IP' constructor, but unlike its base class it can also ++ be called without any arguments. The daemon will then set up a + listen queue of 5 connections and allocate some random port number. + + A server that wants to bind to some specific address on the standard +@@ -57,8 +57,8 @@ DESCRIPTION + LocalPort => 80, + ); + +- See IO::Socket::INET for a description of other arguments that can +- be used configure the daemon during construction. ++ See IO::Socket::IP for a description of other arguments that can be ++ used configure the daemon during construction. + + $c = $d->accept + $c = $d->accept( $pkg ) +@@ -71,7 +71,7 @@ DESCRIPTION + + The accept method will return `undef' if timeouts have been enabled + and no connection is made within the given time. The timeout() +- method is described in IO::Socket. ++ method is described in IO::Socket::IP. + + In list context both the client object and the peer address will be + returned; see the description of the accept method IO::Socket for +@@ -89,9 +89,9 @@ DESCRIPTION + The default is the string "libwww-perl-daemon/#.##" where "#.##" is + replaced with the version number of this module. + +- The `HTTP::Daemon::ClientConn' is a `IO::Socket::INET' subclass. +- Instances of this class are returned by the accept() method of +- `HTTP::Daemon'. The following methods are provided: ++ The `HTTP::Daemon::ClientConn' is a `IO::Socket::IP' subclass. Instances ++ of this class are returned by the accept() method of `HTTP::Daemon'. The ++ following methods are provided: + + $c->get_request + $c->get_request( $headers_only ) +@@ -227,7 +227,7 @@ DESCRIPTION + SEE ALSO + RFC 2616 + +- IO::Socket::INET, IO::Socket ++ IO::Socket::IP, IO::Socket + + COPYRIGHT + Copyright 1996-2003, Gisle Aas +diff --git a/lib/HTTP/Daemon.pm b/lib/HTTP/Daemon.pm +index 27a7bf4..0e22b77 100644 +--- a/lib/HTTP/Daemon.pm ++++ b/lib/HTTP/Daemon.pm +@@ -5,8 +5,10 @@ use vars qw($VERSION @ISA $PROTO $DEBUG); + + $VERSION = "6.01"; + +-use IO::Socket qw(AF_INET INADDR_ANY INADDR_LOOPBACK inet_ntoa); +-@ISA=qw(IO::Socket::INET); ++use Socket qw(AF_INET AF_INET6 INADDR_ANY IN6ADDR_ANY ++ INADDR_LOOPBACK IN6ADDR_LOOPBACK inet_ntop sockaddr_family); ++use IO::Socket::IP; ++@ISA=qw(IO::Socket::IP); + + $PROTO = "HTTP/1.1"; + +@@ -40,15 +42,26 @@ sub url + my $self = shift; + my $url = $self->_default_scheme . "://"; + my $addr = $self->sockaddr; +- if (!$addr || $addr eq INADDR_ANY) { ++ if (!$addr || $addr eq INADDR_ANY || $addr eq IN6ADDR_ANY) { + require Sys::Hostname; + $url .= lc Sys::Hostname::hostname(); + } + elsif ($addr eq INADDR_LOOPBACK) { +- $url .= inet_ntoa($addr); ++ $url .= inet_ntop(AF_INET, $addr); ++ } ++ elsif ($addr eq IN6ADDR_LOOPBACK) { ++ $url .= '[' . inet_ntop(AF_INET6, $addr) . ']'; + } + else { +- $url .= gethostbyaddr($addr, AF_INET) || inet_ntoa($addr); ++ my $host = $addr->sockhostname; ++ if (!defined $host) { ++ if (sockaddr_family($addr) eq AF_INET6) { ++ $host = '[' . inet_ntop(AF_INET6, $addr) . ']'; ++ } else { ++ $host = inet_ntop(AF_INET6, $addr); ++ } ++ } ++ $url .= $host; + } + my $port = $self->sockport; + $url .= ":$port" if $port != $self->_default_port; +@@ -77,8 +90,8 @@ sub product_tokens + package HTTP::Daemon::ClientConn; + + use vars qw(@ISA $DEBUG); +-use IO::Socket (); +-@ISA=qw(IO::Socket::INET); ++use IO::Socket::IP (); ++@ISA=qw(IO::Socket::IP); + *DEBUG = \$HTTP::Daemon::DEBUG; + + use HTTP::Request (); +@@ -645,12 +658,12 @@ HTTP::Daemon - a simple http server class + + Instances of the C class are HTTP/1.1 servers that + listen on a socket for incoming requests. The C is a +-subclass of C, so you can perform socket operations ++subclass of C, so you can perform socket operations + directly on it too. + + The accept() method will return when a connection from a client is + available. The returned value will be an C +-object which is another C subclass. Calling the ++object which is another C subclass. Calling the + get_request() method on this object will read data from the client and + return an C object. The ClientConn object also provide + methods to send back various responses. +@@ -661,7 +674,7 @@ desirable. Also note that the user is responsible for generating + responses that conform to the HTTP/1.1 protocol. + + The following methods of C are new (or enhanced) relative +-to the C base class: ++to the C base class: + + =over 4 + +@@ -670,7 +683,7 @@ to the C base class: + =item $d = HTTP::Daemon->new( %opts ) + + The constructor method takes the same arguments as the +-C constructor, but unlike its base class it can also ++C constructor, but unlike its base class it can also + be called without any arguments. The daemon will then set up a listen + queue of 5 connections and allocate some random port number. + +@@ -682,7 +695,7 @@ HTTP port will be constructed like this: + LocalPort => 80, + ); + +-See L for a description of other arguments that can ++See L for a description of other arguments that can + be used configure the daemon during construction. + + =item $c = $d->accept +@@ -699,7 +712,7 @@ class a subclass of C. + + The accept method will return C if timeouts have been enabled + and no connection is made within the given time. The timeout() method +-is described in L. ++is described in L. + + In list context both the client object and the peer address will be + returned; see the description of the accept method L for +@@ -721,7 +734,7 @@ replaced with the version number of this module. + + =back + +-The C is a C ++The C is a C + subclass. Instances of this class are returned by the accept() method + of C. The following methods are provided: + +@@ -895,7 +908,7 @@ Return a reference to the corresponding C object. + + RFC 2616 + +-L, L ++L, L + + =head1 COPYRIGHT + +diff --git a/t/chunked.t b/t/chunked.t +index e11799f..c274b11 100644 +--- a/t/chunked.t ++++ b/t/chunked.t +@@ -95,18 +95,30 @@ my $can_fork = $Config{d_fork} || + my $tests = @TESTS; + my $tport = 8333; + +-my $tsock = IO::Socket::INET->new(LocalAddr => '0.0.0.0', +- LocalPort => $tport, +- Listen => 1, +- ReuseAddr => 1); ++my @addresses = ( ++ { server => '::', client => '::1' }, ++ { server => '0.0.0.0', client => '127.0.0.1' } ++); ++my $family; ++for my $id (0..$#addresses) { ++ my $tsock = IO::Socket::IP->new(LocalAddr => $addresses[$id]->{server}, ++ LocalPort => $tport, ++ Listen => 1, ++ ReuseAddr => 1); ++ if ($tsock) { ++ close $tsock; ++ $family = $id; ++ last; ++ } ++} ++ + if (!$can_fork) { + plan skip_all => "This system cannot fork"; + } +-elsif (!$tsock) { +- plan skip_all => "Cannot listen on 0.0.0.0:$tport"; ++elsif (!defined $family) { ++ plan skip_all => "Cannot listen on unspecifed address and port $tport"; + } + else { +- close $tsock; + plan tests => $tests; + } + +@@ -132,9 +144,9 @@ if ($pid = fork) { + open my $fh, "| socket localhost $tport" or die; + print $fh $test; + } +- use IO::Socket::INET; +- my $sock = IO::Socket::INET->new( +- PeerAddr => "127.0.0.1", ++ use IO::Socket::IP; ++ my $sock = IO::Socket::IP->new( ++ PeerAddr => $addresses[$family]->{client}, + PeerPort => $tport, + ) or die; + if (0) { +@@ -158,7 +170,7 @@ if ($pid = fork) { + } else { + die "cannot fork: $!" unless defined $pid; + my $d = HTTP::Daemon->new( +- LocalAddr => '0.0.0.0', ++ LocalAddr => $addresses[$family]->{server}, + LocalPort => $tport, + ReuseAddr => 1, + ) or die; +-- +2.7.4 + diff --git a/SOURCES/HTTP-Daemon-6.01-Handle-undef-and-empty-LocalAddr.patch b/SOURCES/HTTP-Daemon-6.01-Handle-undef-and-empty-LocalAddr.patch new file mode 100644 index 0000000..f6fe289 --- /dev/null +++ b/SOURCES/HTTP-Daemon-6.01-Handle-undef-and-empty-LocalAddr.patch @@ -0,0 +1,48 @@ +From b54702ab21edbf1ea0dbc00d978aecc89e5764d6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= +Date: Mon, 18 Sep 2017 15:21:16 +0200 +Subject: [PATCH] Handle undef and empty LocalAddr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +IO::Socket::INET interprets undefined and empty string LocalAddr +arguments as an unspecified address while IO::Socket::IP returns an +error. This seems to be one of the differences between the two +Socket implementations. Recent IO::Socket::IP (0.39) accepts undefined +value, but still bail outs on an empty string. + +To improve compatibility, this patch adds a special handling for these +two values to be accepted as an unspecified value. Though this should +be corrected on IO::Socket:IP side probably. + +CPAN RT#91699 +CPAN RT#123069 + +Signed-off-by: Petr Písař +--- + lib/HTTP/Daemon.pm | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/lib/HTTP/Daemon.pm b/lib/HTTP/Daemon.pm +index 0e22b77..1e9d48e 100644 +--- a/lib/HTTP/Daemon.pm ++++ b/lib/HTTP/Daemon.pm +@@ -18,6 +18,14 @@ sub new + my($class, %args) = @_; + $args{Listen} ||= 5; + $args{Proto} ||= 'tcp'; ++ # Handle undefined or empty local address the same way as ++ # IO::Socket::INET -- use unspecified address ++ for my $key (qw(LocalAddr LocalHost)) { ++ if (exists $args{$key} && ++ (!defined($args{$key}) || $args{$key} eq '')) { ++ delete $args{$key}; ++ } ++ } + return $class->SUPER::new(%args); + } + +-- +2.13.5 + diff --git a/SOURCES/HTTP-Daemon-6.01-Resolve-specific-socket-addresses-correctly.patch b/SOURCES/HTTP-Daemon-6.01-Resolve-specific-socket-addresses-correctly.patch new file mode 100644 index 0000000..ef1ff87 --- /dev/null +++ b/SOURCES/HTTP-Daemon-6.01-Resolve-specific-socket-addresses-correctly.patch @@ -0,0 +1,55 @@ +From e49f553aa8be21e5df72452e50af2e9f0b82ecad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= +Date: Wed, 23 May 2018 17:31:42 +0200 +Subject: [PATCH] Resolve specific socket addresses correctly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Previous code did not formatted specific (not 0.0.0.0 or ::) +correctly: + +$ perl -MHTTP::Daemon -e '$d=HTTP::Daemon->new(LocalAddr=>q{127.0.0.2}) or die; print $d->url, qq{\n}' +Can't call method "sockhostname" without a package or object reference at /usr/share/perl5/vendor_perl/HTTP/Daemon.pm line 64. + +This patch also fixes formatting numerical IPv6 addresses. It seems +that IO::Socket::IP::sockhostname() formats unresolvable addresses too. + +Signed-off-by: Petr Písař +--- + lib/HTTP/Daemon.pm | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/lib/HTTP/Daemon.pm b/lib/HTTP/Daemon.pm +index 1e9d48e..216c73f 100644 +--- a/lib/HTTP/Daemon.pm ++++ b/lib/HTTP/Daemon.pm +@@ -61,12 +61,23 @@ sub url + $url .= '[' . inet_ntop(AF_INET6, $addr) . ']'; + } + else { +- my $host = $addr->sockhostname; ++ my $host = $self->sockhostname; ++ # sockhostname() seems to return a stringified IP address if not ++ # resolvable, then quote it for a port separator and an IPv6 zone separator. ++ # But be paranoid for a case when it already contains a bracket. ++ if (defined $host and $host =~ /:/) { ++ if ($host =~ /[\[\]]/) { ++ $host = undef; ++ } else { ++ $host =~ s/%/%25/g; ++ $host = '[' . $host . ']'; ++ } ++ } + if (!defined $host) { + if (sockaddr_family($addr) eq AF_INET6) { + $host = '[' . inet_ntop(AF_INET6, $addr) . ']'; + } else { +- $host = inet_ntop(AF_INET6, $addr); ++ $host = inet_ntop(AF_INET, $addr); + } + } + $url .= $host; +-- +2.14.3 + diff --git a/SPECS/perl-HTTP-Daemon.spec b/SPECS/perl-HTTP-Daemon.spec new file mode 100644 index 0000000..7a7ccd5 --- /dev/null +++ b/SPECS/perl-HTTP-Daemon.spec @@ -0,0 +1,166 @@ +Name: perl-HTTP-Daemon +Version: 6.01 +Release: 23%{?dist} +Summary: Simple HTTP server class +License: GPL+ or Artistic +URL: http://search.cpan.org/dist/HTTP-Daemon/ +Source0: http://www.cpan.org/authors/id/G/GA/GAAS/HTTP-Daemon-%{version}.tar.gz +# Support IPv6, bug #1413065, CPAN RT#91699, CPAN RT#71395, +# proposed to upstream +Patch0: HTTP-Daemon-6.01-Add-IPv6-support.patch +# Accept undefined and empty-string LocalAddr as IO::Socket::INET does, +# CPAN RT#91699, CPAN RT#123069 +Patch1: HTTP-Daemon-6.01-Handle-undef-and-empty-LocalAddr.patch +# Fix formatting specific non-local addresses, bug #1578026, CPAN RT#125242 +Patch2: HTTP-Daemon-6.01-Resolve-specific-socket-addresses-correctly.patch +BuildArch: noarch +BuildRequires: make +BuildRequires: perl-generators +BuildRequires: perl-interpreter +BuildRequires: perl(:VERSION) >= 5.8.1 +BuildRequires: perl(ExtUtils::MakeMaker) >= 6.76 +BuildRequires: perl(strict) +# Run-time: +BuildRequires: perl(Carp) +BuildRequires: perl(HTTP::Date) >= 6 +BuildRequires: perl(HTTP::Request) >= 6 +BuildRequires: perl(HTTP::Response) >= 6 +BuildRequires: perl(HTTP::Status) >= 6 +BuildRequires: perl(IO::Socket::IP) +BuildRequires: perl(LWP::MediaTypes) >= 6 +BuildRequires: perl(Socket) +BuildRequires: perl(Sys::Hostname) +BuildRequires: perl(vars) +# Tests only: +BuildRequires: perl(Config) +# IO::Socket not used +# LWP::RobotUA not used +# LWP::UserAgent not used +# Test not used +BuildRequires: perl(Test::More) +# URI not used +BuildRequires: perl(warnings) +Requires: perl(:MODULE_COMPAT_%(eval "`perl -V:version`"; echo $version)) +Requires: perl(HTTP::Date) >= 6 +Requires: perl(HTTP::Request) >= 6 +Requires: perl(HTTP::Response) >= 6 +Requires: perl(HTTP::Status) >= 6 +Requires: perl(LWP::MediaTypes) >= 6 +Requires: perl(Sys::Hostname) +Conflicts: perl-libwww-perl < 6 + +# Remove underspecified dependencies +%global __requires_exclude %{?__requires_exclude:%{__requires_exclude}|}^perl\\(HTTP::(Date|Request|Response|Status)|LWP::MediaTypes\\)$ + +%description +Instances of the HTTP::Daemon class are HTTP/1.1 servers that listen on a +socket for incoming requests. The HTTP::Daemon is a subclass of +IO::Socket::IP, so you can perform socket operations directly on it too. + +%prep +%setup -q -n HTTP-Daemon-%{version} +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 + +%build +perl Makefile.PL INSTALLDIRS=vendor NO_PACKLIST=1 +make %{?_smp_mflags} + +%install +make pure_install DESTDIR=%{buildroot} +%{_fixperms} %{buildroot}/* + +%check +make test + +%files +%doc Changes README +%{perl_vendorlib}/* +%{_mandir}/man3/* + +%changelog +* Wed May 23 2018 Petr Pisar - 6.01-23 +- Fix formatting numerical non-local specific IPv6 addresses (bug #1578026) + +* Tue May 15 2018 Jitka Plesnikova - 6.01-22 +- Call "sockhostname" method on correct class object (bug #1578026) + +* Thu Feb 08 2018 Fedora Release Engineering - 6.01-21 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Wed Jan 24 2018 Petr Pisar - 6.01-20 +- Correct the package description + +* Mon Sep 18 2017 Petr Pisar - 6.01-19 +- Correct a typo in the undefined and empty-string LocalAddr patch + (bug #1413065) + +* Mon Sep 18 2017 Petr Pisar - 6.01-18 +- Accept undefined and empty-string LocalAddr as IO::Socket::INET does + (bug #1413065) + +* Thu Jul 27 2017 Fedora Release Engineering - 6.01-17 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Sun Jun 04 2017 Jitka Plesnikova - 6.01-16 +- Perl 5.26 rebuild + +* Sat Feb 11 2017 Fedora Release Engineering - 6.01-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Tue Jan 17 2017 Petr Pisar - 6.01-14 +- Support IPv6 (bug #1413065) + +* Sun May 15 2016 Jitka Plesnikova - 6.01-13 +- Perl 5.24 rebuild + +* Thu Feb 04 2016 Fedora Release Engineering - 6.01-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Thu Jun 18 2015 Fedora Release Engineering - 6.01-11 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Sat Jun 06 2015 Jitka Plesnikova - 6.01-10 +- Perl 5.22 rebuild + +* Thu Aug 28 2014 Jitka Plesnikova - 6.01-9 +- Perl 5.20 rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 6.01-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Sat Aug 03 2013 Fedora Release Engineering - 6.01-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Mon Jul 22 2013 Petr Pisar - 6.01-6 +- Perl 5.18 rebuild + +* Thu Feb 14 2013 Fedora Release Engineering - 6.01-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Tue Nov 13 2012 Petr Šabata - 6.01-4 +- Modernize the spec, fix dependencies, and drop command macros + +* Fri Jul 20 2012 Fedora Release Engineering - 6.01-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Jun 12 2012 Petr Pisar - 6.01-2 +- Perl 5.16 rebuild + +* Mon Feb 20 2012 Petr Pisar - 6.01-1 +- 6.01 bump + +* Fri Jan 13 2012 Fedora Release Engineering - 6.00-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Mon Jul 25 2011 Marcela Mašláňová - 6.00-3 +- add new filter + +* Tue Jun 21 2011 Marcela Mašláňová - 6.00-2 +- Perl mass rebuild + +* Thu Mar 17 2011 Petr Pisar 6.00-1 +- Specfile autogenerated by cpanspec 1.78. +- Remove BuildRoot stuff +- Conflicts with perl-libwww-perl-5* and older