]>
iEval git - app-fonbot-daemon.git/blob - HTTPD.pm
785a0e757501b0e390469b13e1710da099508a33
1 package App
:: FonBot
:: Plugin
:: HTTPD
;
3 our $VERSION = '0.000_5' ;
9 use Apache2
:: Authen
:: Passphrase qw
/pwcheck/ ;
10 use HTTP
:: Status qw
/HTTP_BAD_REQUEST HTTP_OK HTTP_NO_CONTENT HTTP_FORBIDDEN HTTP_UNAUTHORIZED/ ;
11 use JSON qw
/encode_json/ ;
13 use POE
:: Component
:: Server
:: HTTP qw
/RC_OK RC_DENY RC_WAIT/ ;
16 use MIME
:: Base64 qw
/decode_base64/ ;
17 use Storable qw
/freeze thaw/ ;
18 use Text
:: ParseWords qw
/shellwords/ ;
20 use App
:: FonBot
:: Plugin
:: Config qw
/$httpd_port/ ;
21 use App
:: FonBot
:: Plugin
:: Common
;
23 ##################################################
25 my $log = Log
:: Log4perl
-> get_logger ( __PACKAGE__
);
28 my %waiting_userrequests ;
32 $log -> info ( 'initializing ' . __PACKAGE__
);
33 %waiting_requests = ();
34 %waiting_userrequests = ();
35 $httpd = POE
:: Component
:: Server
:: HTTP
-> new (
37 PreHandler
=> { '/' => [ \
& pre_auth
, \
& pre_get
, \
& pre_userget
], },
38 ContentHandler
=>{ '/send' => \
& on_send
, '/get' => \
& on_get
, '/ok' => \
& on_ok
, '/userget' => \
& on_userget
, '/usersend' => \
& on_usersend
},
39 ErrorHandler
=> { '/' => sub { RC_OK
}},
40 Headers
=> { 'Cache-Control' => 'no-cache' },
45 $log -> info ( 'finishing ' . __PACKAGE__
);
46 POE
:: Kernel
-> call ( $httpd , 'shutdown' );
49 ##################################################
52 my ( $response , $errstr , $errcode )= @_ ;
54 $ $response -> code ( $errcode // HTTP_BAD_REQUEST
);
55 $ $response -> header ( Content_Type
=> 'text/plain' );
56 $ $response -> message ( $errstr );
62 my ( $request , $response )= @_ ;
65 my $authorization = $request -> header ( 'Authorization' ) // die 'No Authorization header' ;
66 $authorization =~ /^Basic (.+)$/ or die 'Invalid Authorization header' ;
67 my ( $user , $password ) = decode_base64
( $1 ) =~ /^(.+):(.*)$/ or die 'Invalid Authorization header' ;
68 eval { pwcheck
$user , $password ; 1 } or die 'Invalid user/password combination' ;
69 $request -> header ( Username
=> $user );
70 $log -> debug ( "HTTP request from $user to url " . $request -> url );
73 $response -> code ( HTTP_UNAUTHORIZED
);
74 $response -> message ( 'Bad username or password' );
75 $response -> header ( Content_Type
=> 'text/plain' );
76 $response -> header ( WWW_Authenticate
=> 'Basic realm="fonbotd"' );
77 $response -> content ( 'Unauthorized' );
78 $log -> debug ( "Request denied: $error " );
82 $response -> content ( '' );
87 my ( $request , $response )= @_ ;
88 my $user = $request -> header ( 'Username' );
89 return RC_OK
if $response -> code ;
90 return RC_OK
unless $user ;
91 return RC_OK
unless $request -> uri =~ m
,/ get
,;
93 unless ( exists $commands { $user }) {
94 $log -> debug ( "No pending commands for $user , entering RC_WAIT" );
95 $waiting_requests { $user }-> continue if exists $waiting_requests { $user };
96 $waiting_requests { $user }= $response ;
104 my ( $request , $response )= @_ ;
105 my $user = $request -> header ( 'Username' );
106 return RC_OK
if $response -> code ;
107 return RC_OK
unless $user ;
108 return RC_OK
unless $request -> uri =~ m
,/ userget
,;
110 unless ( exists $responses { $user }) {
111 $log -> debug ( "No pending responses for $user , entering RC_WAIT" );
112 $waiting_userrequests { $user }-> continue if exists $waiting_userrequests { $user };
113 $waiting_userrequests { $user }= $response ;
121 my ( $request , $response )= @_ ;
122 return RC_OK
if $response -> code ;
124 $response -> code ( HTTP_OK
);
129 my ( $request , $response )= @_ ;
130 return RC_OK
if $response -> code ;
133 my $user = $request -> header ( 'Username' );
134 $log -> debug ( "on_get from user $user " );
136 if ( exists $commands { $user }) {
137 my $json = encode_json thaw
$commands { $user };
138 $log -> debug ( "Sending JSON: $json to $user " );
139 $response -> content ( $json );
140 $response -> code ( HTTP_OK
);
141 $response -> message ( 'Commands sent' );
143 $log -> debug ( "Sending back 204 No Content" );
144 $response -> code ( HTTP_NO_CONTENT
);
145 $response -> message ( 'No pending commands' );
148 delete $commands { $user }
151 $log -> error ( "ERROR: $@" ) if $ @
&& $ @
!~ /^Bad Request / ;
157 my ( $request , $response )= @_ ;
158 return RC_OK
if $response -> code ;
161 my $user = $request -> header ( 'Username' );
162 $log -> debug ( "on_userget from user $user " );
164 if ( exists $responses { $user }) {
165 my $json = encode_json
$responses { $user };
166 $log -> debug ( "Sending JSON: $json to $user " );
167 $response -> content ( $json );
168 $response -> code ( HTTP_OK
);
169 $response -> message ( 'Responses sent' );
171 $log -> debug ( "Sending back 204 No Content" );
172 $response -> code ( HTTP_NO_CONTENT
);
173 $response -> message ( 'No pending responses' );
176 delete $responses { $user }
179 $log -> error ( "ERROR: $@" ) if $ @
&& $ @
!~ /^Bad Request / ;
185 my ( $request , $response )= @_ ;
186 return RC_OK
if $response -> code ;
189 httpdie
$response , 'All requests must use the POST http method' unless $request -> method eq 'POST' ;
190 my $user = $request -> header ( 'Username' );
192 my $destination = $request -> header ( 'X-Destination' ) // httpdie
$response , 'Missing destination address' ;
193 my ( $driver , $address )= shellwords
$destination ;
195 my $content = $request -> content // httpdie
$response , 'Content is undef' ;
197 if ( $driver eq 'HTTP' ) {
198 $responses { $user } // =[];
199 push $responses { $user }, $content ;
200 if ( exists $waiting_userrequests { $user }) {
201 $waiting_userrequests { $user }-> continue ;
202 delete $waiting_userrequests { $user }
205 unless ( $ok_user_addresses { " $user $driver $address " }) {
206 $response -> code ( HTTP_FORBIDDEN
);
207 $response -> message ( " $user is not allowed to send messages to $address " );
211 POE
:: Kernel
-> post ( $driver , 'send_message' , $address , $content ) or $log -> error ( "Driver not found: $driver " );
214 $response -> code ( HTTP_NO_CONTENT
);
215 $response -> message ( 'Message sent' );
218 $log -> error ( "ERROR: $@" ) if $ @
&& $ @
!~ /^Bad Request / ;
219 $log -> debug ( 'Responding to send from $user with ' . $response -> code . ' ' . $response -> message );
224 my ( $request , $response )= @_ ;
225 $log -> debug ( "asdasd asd" );
226 return RC_OK
if $response -> code ;
229 httpdie
$response , 'All requests must use the POST http method' unless $request -> method eq 'POST' ;
230 my $user = $request -> header ( 'Username' );
232 my $content = $request -> content // httpdie
$response , 'Content is undef' ;
234 sendmsg
$user , $request -> header ( 'X-Requestid' ), HTTP
=> shellwords
$_ for split ' \n ' , $content ;
236 $response -> code ( HTTP_NO_CONTENT
);
237 $response -> message ( 'Command sent' );
240 $log -> error ( "ERROR: $@" ) if $ @
&& $ @
!~ /^Bad Request / ;
241 $log -> debug ( 'Responding to usersend from $user with ' . $response -> code . ' ' . $response -> message );
252 App::FonBot::Plugin::HTTPD - FonBot webserver plugin, used for communication with phones
256 use App::FonBot::Plugin::HTTPD;
257 App::FonBot::Plugin::HTTPD->init;
259 App::FonBot::Plugin::HTTPD->fini;
263 This FonBot plugin provides a webserver for interacting with fonbotd. All requests use Basic access authentication.
265 The available calls are:
271 Returns a JSON array of pending commands for the current user. Uses long polling — the server does not respond immediately if there are no pending commands.
279 Sends a message to an address. The address is given in the C<X-Destination> header. The message is in the POST data.
281 =item GET C</userget>
283 Returns a JSON array of pending messages for the current user. Uses long polling — the server does not respond immediately if there are no pending commands.
285 =item POST C</usersend>
287 Sends a command to the sender's phone. The optional C<X-Requestid> header sets the request ID. The command is in the POST data
291 =head1 CONFIGURATION VARIABLES
297 The HTTPD listens on this port.
303 Marius Gavrilescu C<< marius@ieval.ro >>
305 =head1 COPYRIGHT AND LICENSE
307 Copyright 2013 Marius Gavrilescu
309 This file is part of fonbotd.
311 fonbotd is free software: you can redistribute it and/or modify
312 it under the terms of the GNU Affero General Public License as published by
313 the Free Software Foundation, either version 3 of the License, or
314 (at your option) any later version.
316 fonbotd is distributed in the hope that it will be useful,
317 but WITHOUT ANY WARRANTY; without even the implied warranty of
318 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
319 GNU Affero General Public License for more details.
321 You should have received a copy of the GNU Affero General Public License
322 along with fonbotd. If not, see <http://www.gnu.org/licenses/>
This page took 0.069608 seconds and 3 git commands to generate.