| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Haineko::HTTPD; | 
| 2 | 10 |  |  | 10 |  | 6008 | use feature ':5.10'; | 
|  | 10 |  |  |  |  | 19 |  | 
|  | 10 |  |  |  |  | 1610 |  | 
| 3 | 10 |  |  | 10 |  | 142 | use strict; | 
|  | 10 |  |  |  |  | 20 |  | 
|  | 10 |  |  |  |  | 6091 |  | 
| 4 | 10 |  |  | 10 |  | 51 | use warnings; | 
|  | 10 |  |  |  |  | 27 |  | 
|  | 10 |  |  |  |  | 606 |  | 
| 5 | 10 |  |  | 10 |  | 11117 | use Try::Tiny; | 
|  | 10 |  |  |  |  | 19004 |  | 
|  | 10 |  |  |  |  | 767 |  | 
| 6 | 10 |  |  | 10 |  | 10734 | use Path::Class; | 
|  | 10 |  |  |  |  | 753056 |  | 
|  | 10 |  |  |  |  | 803 |  | 
| 7 | 10 |  |  | 10 |  | 5891 | use Haineko::JSON; | 
|  | 10 |  |  |  |  | 38 |  | 
|  | 10 |  |  |  |  | 507 |  | 
| 8 | 10 |  |  | 10 |  | 8047 | use Haineko::Default; | 
|  | 10 |  |  |  |  | 25 |  | 
|  | 10 |  |  |  |  | 266 |  | 
| 9 | 10 |  |  | 10 |  | 6212 | use Class::Accessor::Lite; | 
|  | 10 |  |  |  |  | 8050 |  | 
|  | 10 |  |  |  |  | 92 |  | 
| 10 | 10 |  |  | 10 |  | 6658 | use Haineko::HTTPD::Router; | 
|  | 10 |  |  |  |  | 34 |  | 
|  | 10 |  |  |  |  | 653 |  | 
| 11 | 10 |  |  | 10 |  | 14506 | use Haineko::HTTPD::Request; | 
|  | 10 |  |  |  |  | 32 |  | 
|  | 10 |  |  |  |  | 302 |  | 
| 12 | 10 |  |  | 10 |  | 8079 | use Haineko::HTTPD::Response; | 
|  | 10 |  |  |  |  | 32 |  | 
|  | 10 |  |  |  |  | 18640 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | my $rwaccessors = [ | 
| 15 |  |  |  |  |  |  | 'debug',    # (Integer) $HAINEKO_DEBUG | 
| 16 |  |  |  |  |  |  | 'router',   # (Haineko::HTTPD::Router) Routing table | 
| 17 |  |  |  |  |  |  | 'request',  # (Haineko::HTTPD::Request) HTTP Request | 
| 18 |  |  |  |  |  |  | 'response', # (Haineko::HTTPD::Response) HTTP Response | 
| 19 |  |  |  |  |  |  | ]; | 
| 20 |  |  |  |  |  |  | my $roaccessors = [ | 
| 21 |  |  |  |  |  |  | 'name',     # (String) System name | 
| 22 |  |  |  |  |  |  | 'host',     # (String) SERVER_NAME | 
| 23 |  |  |  |  |  |  | 'conf',     # (Ref->Hash) Haineko Configuration | 
| 24 |  |  |  |  |  |  | 'root',     # (Path::Class::Dir) Root directory | 
| 25 |  |  |  |  |  |  | ]; | 
| 26 |  |  |  |  |  |  | my $woaccessors = []; | 
| 27 |  |  |  |  |  |  | Class::Accessor::Lite->mk_accessors( @$rwaccessors ); | 
| 28 |  |  |  |  |  |  | Class::Accessor::Lite->mk_ro_accessors( @$roaccessors ); | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | sub new { | 
| 31 | 18 |  |  | 18 | 1 | 53 | my $class = shift; | 
| 32 | 18 |  |  |  |  | 77 | my $argvs = { @_ }; | 
| 33 |  |  |  |  |  |  |  | 
| 34 | 18 |  | 50 |  |  | 237 | my $hainekodir = $argvs->{'root'} || $ENV{'HAINEKO_ROOT'} || '.'; | 
| 35 | 18 |  | 50 |  |  | 193 | my $hainekocfg = $argvs->{'conf'} || $ENV{'HAINEKO_CONF'} || q(); | 
| 36 | 18 |  |  |  |  | 42 | my $milterlibs = []; | 
| 37 |  |  |  |  |  |  |  | 
| 38 | 18 |  |  |  |  | 57 | $argvs->{'name'} = 'Haineko'; | 
| 39 | 18 | 50 |  |  |  | 261 | $argvs->{'root'} = Path::Class::Dir->new( $hainekodir ) if $hainekodir; | 
| 40 | 18 |  | 33 |  |  | 2355 | $argvs->{'conf'} = Haineko::JSON->loadfile( $hainekocfg ) || Haineko::Default->conf; | 
| 41 | 18 |  | 50 |  |  | 103 | $milterlibs = $argvs->{'conf'}->{'smtpd'}->{'milter'}->{'libs'} || []; | 
| 42 |  |  |  |  |  |  |  | 
| 43 | 18 |  |  |  |  | 60 | for my $e ( 'mailer', 'access' ) { | 
| 44 |  |  |  |  |  |  | # Override configuration files | 
| 45 |  |  |  |  |  |  | #   mailertable files and access controll files are overridden the file | 
| 46 |  |  |  |  |  |  | #   which defined in etc/haineko.cf: | 
| 47 |  |  |  |  |  |  | # | 
| 48 | 36 |  | 33 |  |  | 224 | my $f = $argvs->{'conf'}->{'smtpd'}->{ $e } || Haineko::Default->table( $e ); | 
| 49 | 36 |  |  |  |  | 62 | my $g = undef; | 
| 50 |  |  |  |  |  |  |  | 
| 51 | 36 |  |  |  |  | 126 | for my $ee ( keys %$f ) { | 
| 52 |  |  |  |  |  |  | # etc/{sendermt,mailertable,authinfo}, etc/{relayhosts,recipients} | 
| 53 |  |  |  |  |  |  | # Get an absolute path of each table | 
| 54 |  |  |  |  |  |  | # | 
| 55 | 90 |  |  |  |  | 170 | $g = $f->{ $ee }; | 
| 56 | 90 | 50 |  |  |  | 416 | $g = sprintf( "%s/etc/%s", $hainekodir, $g ) unless $g =~ m|\A[/.]|; | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 90 | 50 |  |  |  | 247 | if( $ENV{'HAINEKO_DEBUG'} ) { | 
| 59 |  |  |  |  |  |  | # When the value of $HAINEKO_DEBUG is 1, | 
| 60 |  |  |  |  |  |  | # etc/{mailertable,authinfo,sendermt,recipients,relayhosts}-debug | 
| 61 |  |  |  |  |  |  | # are used as a configuration files for debugging. | 
| 62 |  |  |  |  |  |  | # | 
| 63 | 0 | 0 |  |  |  | 0 | if( not $g =~ m/[-]debug\z/ ) { | 
| 64 | 0 | 0 |  |  |  | 0 | $g .= '-debug' if -f -s -r $g.'-debug'; | 
| 65 |  |  |  |  |  |  | } | 
| 66 |  |  |  |  |  |  | } | 
| 67 | 90 |  |  |  |  | 374 | $argvs->{'conf'}->{'smtpd'}->{ $e }->{ $ee } = $g; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  | } # End of for(TABLE FILES) | 
| 70 |  |  |  |  |  |  |  | 
| 71 | 18 | 50 |  |  |  | 70 | if( ref $milterlibs eq 'ARRAY' ) { | 
| 72 |  |  |  |  |  |  | # Load milter lib path | 
| 73 | 18 |  |  |  |  | 6983 | require Haineko::SMTPD::Milter; | 
| 74 | 18 |  |  |  |  | 166 | Haineko::SMTPD::Milter->libs( $milterlibs ); | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 18 |  | 33 |  |  | 326 | $argvs->{'router'}   ||= Haineko::HTTPD::Router->new; | 
| 78 | 18 |  | 33 |  |  | 277 | $argvs->{'request'}  ||= Haineko::HTTPD::Request->new; | 
| 79 | 18 |  | 33 |  |  | 288 | $argvs->{'response'} ||= Haineko::HTTPD::Response->new; | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 18 |  |  |  |  | 421 | $argvs->{'host'}  = $argvs->{'request'}->env->{'SERVER_NAME'}; | 
| 82 | 18 | 50 |  |  |  | 189 | $argvs->{'debug'} = $ENV{'HAINEKO_DEBUG'} ? 1 : 0; | 
| 83 |  |  |  |  |  |  |  | 
| 84 | 18 |  |  |  |  | 72 | return bless $argvs, __PACKAGE__; | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | sub start { | 
| 88 | 5 |  |  | 5 | 1 | 94 | my $class = shift; | 
| 89 |  |  |  |  |  |  | my $nyaaa = sub { | 
| 90 | 18 |  |  | 18 |  | 449083 | my $hainekoenv = shift; | 
| 91 | 18 |  |  |  |  | 51 | my $htresponse = undef; | 
| 92 | 18 |  |  |  |  | 306 | my $requestnya = Haineko::HTTPD::Request->new( $hainekoenv ); | 
| 93 | 18 |  |  |  |  | 591 | my $contextnya = $class->new( 'request' => $requestnya ); | 
| 94 |  |  |  |  |  |  |  | 
| 95 | 18 |  |  |  |  | 121 | local *Haineko::HTTPD::context = sub { $contextnya }; | 
|  | 0 |  |  |  |  | 0 |  | 
| 96 | 18 |  |  |  |  | 116 | $htresponse = $class->startup( $contextnya ); | 
| 97 |  |  |  |  |  |  |  | 
| 98 | 18 |  |  |  |  | 217 | return $htresponse->finalize; | 
| 99 | 5 |  |  |  |  | 46 | }; | 
| 100 |  |  |  |  |  |  |  | 
| 101 | 5 |  |  |  |  | 21 | return $nyaaa; | 
| 102 |  |  |  |  |  |  | } | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | sub req { | 
| 105 | 138 |  |  | 138 | 1 | 466 | my $self = shift; | 
| 106 | 138 |  |  |  |  | 392 | return $self->request; | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | sub res { | 
| 110 | 17 |  |  | 17 | 1 | 35 | my $self = shift; | 
| 111 | 17 |  |  |  |  | 72 | return $self->response; | 
| 112 |  |  |  |  |  |  | } | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | sub rdr { | 
| 115 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 116 | 0 |  | 0 |  |  | 0 | my $code = shift || 302; | 
| 117 | 0 |  |  |  |  | 0 | my $next = shift; | 
| 118 |  |  |  |  |  |  |  | 
| 119 | 0 |  |  |  |  | 0 | $self->response->redirect( $next, $code ); | 
| 120 | 0 |  |  |  |  | 0 | return $self->response; | 
| 121 |  |  |  |  |  |  | } | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | sub err { | 
| 124 | 1 |  |  | 1 | 1 | 3 | my $self = shift; | 
| 125 | 1 |  | 50 |  |  | 9 | my $code = shift || 404; | 
| 126 | 1 |  |  |  |  | 3 | my $mesg = shift; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 1 | 50 |  |  |  | 7 | unless( $mesg ) { | 
| 129 |  |  |  |  |  |  | # If the second argument is omitted, use "404 Not found" as a JSON. | 
| 130 | 1 |  |  |  |  | 18 | require Haineko::SMTPD::Response; | 
| 131 | 1 |  |  |  |  | 10 | $mesg = Haineko::SMTPD::Response->r( 'http', 'not-found' )->damn; | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  |  | 
| 134 | 1 | 50 |  |  |  | 10 | if( ref $mesg eq 'HASH' ) { | 
| 135 |  |  |  |  |  |  | # Respond as a JSON | 
| 136 | 1 |  |  |  |  | 6 | require Haineko::SMTPD::Session; | 
| 137 | 1 |  | 50 |  |  | 4 | my $addr = [ split( ',', $self->req->header('X-Forwarded-For') || q() ) ]; | 
| 138 | 1 |  | 50 |  |  | 170 | my $sess = Haineko::SMTPD::Session->new( | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
|  |  |  | 50 |  |  |  |  | 
| 139 |  |  |  |  |  |  | 'referer'    => $self->req->referer // undef, | 
| 140 |  |  |  |  |  |  | 'response'   => [ $mesg ], | 
| 141 |  |  |  |  |  |  | 'remoteaddr' => pop @$addr || $self->req->address // undef, | 
| 142 |  |  |  |  |  |  | 'remoteport' => $self->req->env->{'REMOTE_ADDR'} // undef, | 
| 143 |  |  |  |  |  |  | 'useragent'  => $self->req->user_agent // undef, | 
| 144 |  |  |  |  |  |  | )->damn; | 
| 145 | 1 |  |  |  |  | 10 | $sess->{'queueid'} = undef; | 
| 146 | 1 |  |  |  |  | 6 | return $self->response->json( $code, $sess ); | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | } else { | 
| 149 |  |  |  |  |  |  | # Respond as a text | 
| 150 | 0 |  |  |  |  | 0 | $self->response->code( $code ); | 
| 151 | 0 |  |  |  |  | 0 | $self->response->content_type( 'text/plain' ); | 
| 152 | 0 |  |  |  |  | 0 | $self->response->content_length( length $mesg ); | 
| 153 | 0 |  |  |  |  | 0 | $self->response->body( $mesg ); | 
| 154 | 0 |  |  |  |  | 0 | return $self->response; | 
| 155 |  |  |  |  |  |  | } | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | sub r { | 
| 159 | 18 |  |  | 18 | 1 | 38 | my $self = shift; | 
| 160 | 18 |  |  |  |  | 70 | my $neko = $self->router->routematch( $self->req->env ); | 
| 161 |  |  |  |  |  |  |  | 
| 162 | 18 | 100 |  |  |  | 1926 | return $self->err unless $neko; | 
| 163 |  |  |  |  |  |  |  | 
| 164 | 17 |  |  |  |  | 74 | my $controller = sprintf( "Haineko::%s", $neko->dest->{'controller'} ); | 
| 165 | 17 |  |  |  |  | 158 | my $ctrlaction = $neko->dest->{'action'}; | 
| 166 | 17 |  |  |  |  | 86 | my $exceptions = 0; | 
| 167 | 17 |  |  |  |  | 28 | my $htcontents = undef; | 
| 168 | 17 |  |  |  |  | 75 | my $nekosyslog = undef; | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | try { | 
| 171 | 17 |  |  | 17 |  | 645 | require Module::Load; | 
| 172 | 17 |  |  |  |  | 79 | Module::Load::load( $controller ); | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | } catch { | 
| 175 | 0 |  |  | 0 |  | 0 | require Haineko::Log; | 
| 176 | 0 |  |  |  |  | 0 | require Haineko::SMTPD::Response; | 
| 177 |  |  |  |  |  |  |  | 
| 178 | 0 |  |  |  |  | 0 | $htcontents = Haineko::SMTPD::Response->r( 'http', 'server-error' )->damn; | 
| 179 | 0 |  |  |  |  | 0 | $nekosyslog = Haineko::Log->new( 'disabled' => 0 ); | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 0 |  |  |  |  | 0 | $htcontents->{'message'}->[1] = $_; | 
| 182 | 0 |  |  |  |  | 0 | $nekosyslog->w( 'crit', $htcontents ); | 
| 183 | 0 | 0 |  |  |  | 0 | pop @{ $htcontents->{'message'} } unless $self->debug; | 
|  | 0 |  |  |  |  | 0 |  | 
| 184 | 0 |  |  |  |  | 0 | $exceptions = 1; | 
| 185 | 17 |  |  |  |  | 190 | }; | 
| 186 |  |  |  |  |  |  |  | 
| 187 | 17 | 50 |  |  |  | 1694 | return $controller->$ctrlaction( $self ) unless $exceptions; | 
| 188 | 0 |  |  |  |  |  | return $self->err( 500, { 'response' => $htcontents } ); | 
| 189 |  |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | 1; | 
| 192 |  |  |  |  |  |  | __END__ |