File Coverage

lib/Haineko/HTTPD.pm
Criterion Covered Total %
statement 97 120 80.8
branch 10 24 41.6
condition 15 38 39.4
subroutine 19 21 90.4
pod 7 7 100.0
total 148 210 70.4


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__