line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
############################################################################### |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# This file copyright (c) 2001-2014 Randy J. Ray, all rights reserved |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
# Copying and distribution are permitted under the terms of the Artistic |
6
|
|
|
|
|
|
|
# License 2.0 (http://www.opensource.org/licenses/artistic-license-2.0.php) or |
7
|
|
|
|
|
|
|
# the GNU LGPL (http://www.opensource.org/licenses/lgpl-2.1.php). |
8
|
|
|
|
|
|
|
# |
9
|
|
|
|
|
|
|
############################################################################### |
10
|
|
|
|
|
|
|
# |
11
|
|
|
|
|
|
|
# Description: This class implements an RPC::XML server, using the core |
12
|
|
|
|
|
|
|
# XML::RPC transaction code. The server may be created with |
13
|
|
|
|
|
|
|
# or without an HTTP::Daemon object instance to answer the |
14
|
|
|
|
|
|
|
# requests. |
15
|
|
|
|
|
|
|
# |
16
|
|
|
|
|
|
|
# Functions: new |
17
|
|
|
|
|
|
|
# version |
18
|
|
|
|
|
|
|
# url |
19
|
|
|
|
|
|
|
# product_tokens |
20
|
|
|
|
|
|
|
# started |
21
|
|
|
|
|
|
|
# path |
22
|
|
|
|
|
|
|
# host |
23
|
|
|
|
|
|
|
# port |
24
|
|
|
|
|
|
|
# requests |
25
|
|
|
|
|
|
|
# response |
26
|
|
|
|
|
|
|
# compress |
27
|
|
|
|
|
|
|
# compress_thresh |
28
|
|
|
|
|
|
|
# compress_re |
29
|
|
|
|
|
|
|
# message_file_thresh |
30
|
|
|
|
|
|
|
# message_temp_dir |
31
|
|
|
|
|
|
|
# xpl_path |
32
|
|
|
|
|
|
|
# add_method |
33
|
|
|
|
|
|
|
# method_from_file |
34
|
|
|
|
|
|
|
# get_method |
35
|
|
|
|
|
|
|
# server_loop |
36
|
|
|
|
|
|
|
# post_configure_hook |
37
|
|
|
|
|
|
|
# pre_loop_hook |
38
|
|
|
|
|
|
|
# process_request |
39
|
|
|
|
|
|
|
# dispatch |
40
|
|
|
|
|
|
|
# call |
41
|
|
|
|
|
|
|
# add_default_methods |
42
|
|
|
|
|
|
|
# add_methods_in_dir |
43
|
|
|
|
|
|
|
# delete_method |
44
|
|
|
|
|
|
|
# list_methods |
45
|
|
|
|
|
|
|
# share_methods |
46
|
|
|
|
|
|
|
# copy_methods |
47
|
|
|
|
|
|
|
# timeout |
48
|
|
|
|
|
|
|
# server_fault |
49
|
|
|
|
|
|
|
# |
50
|
|
|
|
|
|
|
# Libraries: HTTP::Daemon (conditionally) |
51
|
|
|
|
|
|
|
# HTTP::Response |
52
|
|
|
|
|
|
|
# HTTP::Status |
53
|
|
|
|
|
|
|
# URI |
54
|
|
|
|
|
|
|
# Scalar::Util |
55
|
|
|
|
|
|
|
# RPC::XML |
56
|
|
|
|
|
|
|
# RPC::XML::ParserFactory |
57
|
|
|
|
|
|
|
# RPC::XML::Procedure |
58
|
|
|
|
|
|
|
# Compress::Raw::Zlib is used if available |
59
|
|
|
|
|
|
|
# |
60
|
|
|
|
|
|
|
# Global Consts: $VERSION |
61
|
|
|
|
|
|
|
# $INSTALL_DIR |
62
|
|
|
|
|
|
|
# %FAULT_TABLE |
63
|
|
|
|
|
|
|
# |
64
|
|
|
|
|
|
|
############################################################################### |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
package RPC::XML::Server; |
67
|
|
|
|
|
|
|
|
68
|
8
|
|
|
8
|
|
172917
|
use 5.008008; |
|
8
|
|
|
|
|
18
|
|
69
|
8
|
|
|
8
|
|
26
|
use strict; |
|
8
|
|
|
|
|
8
|
|
|
8
|
|
|
|
|
136
|
|
70
|
8
|
|
|
8
|
|
26
|
use warnings; |
|
8
|
|
|
|
|
10
|
|
|
8
|
|
|
|
|
229
|
|
71
|
8
|
|
|
|
|
619
|
use vars qw($VERSION $INSTALL_DIR %FAULT_TABLE @XPL_PATH %CLASS_MAP |
72
|
8
|
|
|
8
|
|
29
|
$IO_SOCKET_SSL_HACK_NEEDED $COMPRESSION_AVAILABLE); |
|
8
|
|
|
|
|
7
|
|
73
|
|
|
|
|
|
|
|
74
|
8
|
|
|
8
|
|
26
|
use Carp qw(carp croak); |
|
8
|
|
|
|
|
10
|
|
|
8
|
|
|
|
|
369
|
|
75
|
8
|
|
|
8
|
|
31
|
use File::Spec; |
|
8
|
|
|
|
|
7
|
|
|
8
|
|
|
|
|
122
|
|
76
|
8
|
|
|
8
|
|
4336
|
use File::Temp; |
|
8
|
|
|
|
|
82531
|
|
|
8
|
|
|
|
|
530
|
|
77
|
8
|
|
|
8
|
|
38
|
use IO::Handle; |
|
8
|
|
|
|
|
85
|
|
|
8
|
|
|
|
|
233
|
|
78
|
8
|
|
|
8
|
|
1364
|
use Module::Load; |
|
8
|
|
|
|
|
2499
|
|
|
8
|
|
|
|
|
58
|
|
79
|
8
|
|
|
8
|
|
326
|
use Scalar::Util 'blessed'; |
|
8
|
|
|
|
|
10
|
|
|
8
|
|
|
|
|
273
|
|
80
|
|
|
|
|
|
|
|
81
|
8
|
|
|
8
|
|
1722
|
use HTTP::Status; |
|
8
|
|
|
|
|
10182
|
|
|
8
|
|
|
|
|
1500
|
|
82
|
8
|
|
|
8
|
|
1567
|
use HTTP::Response; |
|
8
|
|
|
|
|
36883
|
|
|
8
|
|
|
|
|
159
|
|
83
|
8
|
|
|
8
|
|
29
|
use URI; |
|
8
|
|
|
|
|
9
|
|
|
8
|
|
|
|
|
141
|
|
84
|
|
|
|
|
|
|
|
85
|
8
|
|
|
8
|
|
2773
|
use RPC::XML; |
|
8
|
|
|
|
|
13
|
|
|
8
|
|
|
|
|
325
|
|
86
|
8
|
|
|
8
|
|
2833
|
use RPC::XML::ParserFactory; |
|
8
|
|
|
|
|
11
|
|
|
8
|
|
|
|
|
37
|
|
87
|
8
|
|
|
8
|
|
3120
|
use RPC::XML::Procedure; |
|
8
|
|
|
|
|
16
|
|
|
8
|
|
|
|
|
807
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
BEGIN |
90
|
|
|
|
|
|
|
{ |
91
|
8
|
|
|
8
|
|
257
|
$INSTALL_DIR = |
92
|
|
|
|
|
|
|
File::Spec->catpath((File::Spec->splitpath(__FILE__))[0, 1], q{}); |
93
|
8
|
|
|
|
|
47
|
@XPL_PATH = ($INSTALL_DIR, File::Spec->curdir); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# For now, I have an ugly hack in place to make the functionality that |
96
|
|
|
|
|
|
|
# runs under HTTP::Daemon/Net::Server work better with SSL. This flag |
97
|
|
|
|
|
|
|
# starts out true, then gets set to false the first time the hack is |
98
|
|
|
|
|
|
|
# applied, so that it doesn't get repeated over and over... |
99
|
8
|
|
|
|
|
10
|
$IO_SOCKET_SSL_HACK_NEEDED = 1; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Check for compression support |
102
|
|
|
|
|
|
|
$COMPRESSION_AVAILABLE = |
103
|
8
|
50
|
|
|
|
12
|
(eval { load Compress::Zlib; 1; }) ? 'deflate' : q{}; |
|
8
|
|
|
|
|
27
|
|
|
8
|
|
|
|
|
280188
|
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Set up the initial table of fault-types and their codes/messages |
106
|
8
|
|
|
|
|
55
|
%FAULT_TABLE = ( |
107
|
|
|
|
|
|
|
badxml => [ 100 => 'XML parse error: %s' ], |
108
|
|
|
|
|
|
|
badmethod => [ 200 => 'Method lookup error: %s' ], |
109
|
|
|
|
|
|
|
badsignature => [ 201 => 'Method signature error: %s' ], |
110
|
|
|
|
|
|
|
execerror => [ 300 => 'Code execution error: %s' ], |
111
|
|
|
|
|
|
|
); |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# This is used by add_method to map "types" to instantiation classes |
114
|
8
|
|
|
|
|
6113
|
%CLASS_MAP = ( |
115
|
|
|
|
|
|
|
method => 'RPC::XML::Method', |
116
|
|
|
|
|
|
|
procedure => 'RPC::XML::Procedure', |
117
|
|
|
|
|
|
|
function => 'RPC::XML::Function', |
118
|
|
|
|
|
|
|
); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
$VERSION = '1.73'; |
122
|
|
|
|
|
|
|
$VERSION = eval $VERSION; ## no critic (ProhibitStringyEval) |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
############################################################################### |
125
|
|
|
|
|
|
|
# |
126
|
|
|
|
|
|
|
# Sub Name: new |
127
|
|
|
|
|
|
|
# |
128
|
|
|
|
|
|
|
# Description: Create a new RPC::XML::Server object. This entails getting |
129
|
|
|
|
|
|
|
# a HTTP::Daemon object, saving several internal values, and |
130
|
|
|
|
|
|
|
# other operations. |
131
|
|
|
|
|
|
|
# |
132
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
133
|
|
|
|
|
|
|
# $class in scalar Ref or string for the class |
134
|
|
|
|
|
|
|
# %args in hash Additional arguments |
135
|
|
|
|
|
|
|
# |
136
|
|
|
|
|
|
|
# Returns: Success: object reference |
137
|
|
|
|
|
|
|
# Failure: error string |
138
|
|
|
|
|
|
|
# |
139
|
|
|
|
|
|
|
############################################################################### |
140
|
|
|
|
|
|
|
sub new ## no critic (ProhibitExcessComplexity) |
141
|
|
|
|
|
|
|
{ |
142
|
5
|
|
|
5
|
1
|
15400
|
my ($class, %args) = @_; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
my ( |
145
|
5
|
|
|
|
|
6
|
$self, $http, $resp, $host, $port, $queue, $URI, $srv_version, |
146
|
|
|
|
|
|
|
$srv_name |
147
|
|
|
|
|
|
|
); |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# Don't accept a blessed value for $class |
150
|
5
|
100
|
|
|
|
27
|
if (ref $class) |
151
|
|
|
|
|
|
|
{ |
152
|
1
|
|
|
|
|
3
|
return __PACKAGE__ . '::new: Must be called as a static method'; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
4
|
|
|
|
|
10
|
$self = bless {}, $class; |
156
|
|
|
|
|
|
|
|
157
|
4
|
|
33
|
|
|
28
|
$srv_version = delete $args{server_version} || $self->version; |
158
|
4
|
|
33
|
|
|
20
|
$srv_name = delete $args{server_name} || $class; |
159
|
4
|
|
|
|
|
49
|
$self->{__server_token} = "$srv_name/$srv_version"; |
160
|
|
|
|
|
|
|
|
161
|
4
|
100
|
|
|
|
13
|
if (delete $args{no_http}) |
162
|
|
|
|
|
|
|
{ |
163
|
1
|
|
50
|
|
|
6
|
$self->{__host} = delete $args{host} || q{}; |
164
|
1
|
|
50
|
|
|
4
|
$self->{__port} = delete $args{port} || q{}; |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
else |
167
|
|
|
|
|
|
|
{ |
168
|
3
|
|
|
|
|
1326
|
require HTTP::Daemon; |
169
|
|
|
|
|
|
|
|
170
|
3
|
|
100
|
|
|
44491
|
$host = delete $args{host} || q{}; |
171
|
3
|
|
50
|
|
|
18
|
$port = delete $args{port} || q{}; |
172
|
3
|
|
50
|
|
|
15
|
$queue = delete $args{queue} || 5; |
173
|
3
|
100
|
|
|
|
27
|
$http = HTTP::Daemon->new( |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
174
|
|
|
|
|
|
|
ReuseAddr => 1, |
175
|
|
|
|
|
|
|
($host ? (LocalHost => $host) : ()), |
176
|
|
|
|
|
|
|
($port ? (LocalPort => $port) : ()), |
177
|
|
|
|
|
|
|
($queue ? (Listen => $queue) : ()) |
178
|
|
|
|
|
|
|
); |
179
|
3
|
50
|
|
|
|
1284
|
if (! $http) |
180
|
|
|
|
|
|
|
{ |
181
|
0
|
|
|
|
|
0
|
return "${class}::new: Unable to create HTTP::Daemon object: $@"; |
182
|
|
|
|
|
|
|
} |
183
|
3
|
|
|
|
|
11
|
$URI = URI->new($http->url); |
184
|
3
|
|
|
|
|
17103
|
$self->{__host} = $URI->host; |
185
|
3
|
|
|
|
|
274
|
$self->{__port} = $URI->port; |
186
|
3
|
|
|
|
|
55
|
$self->{__daemon} = $http; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# Create and store the cached response object for later cloning and use |
190
|
4
|
|
|
|
|
34
|
$resp = HTTP::Response->new(); |
191
|
|
|
|
|
|
|
$resp->header( |
192
|
|
|
|
|
|
|
# This is essentially the same string returned by the |
193
|
|
|
|
|
|
|
# default "identity" method that may be loaded from a |
194
|
|
|
|
|
|
|
# XPL file. But it hasn't been loaded yet, and may not |
195
|
|
|
|
|
|
|
# be, hence we set it here (possibly from option values) |
196
|
|
|
|
|
|
|
RPC_Server => $self->{__server_token}, |
197
|
4
|
|
|
|
|
242
|
RPC_Encoding => 'XML-RPC', |
198
|
|
|
|
|
|
|
# Set any other headers as well |
199
|
|
|
|
|
|
|
Accept => 'text/xml' |
200
|
|
|
|
|
|
|
); |
201
|
4
|
|
|
|
|
521
|
$resp->content_type('text/xml'); |
202
|
4
|
|
|
|
|
93
|
$resp->code(RC_OK); |
203
|
4
|
|
|
|
|
30
|
$resp->message('OK'); |
204
|
4
|
|
|
|
|
23
|
$self->{__response} = $resp; |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# Basic (scalar) properties |
207
|
4
|
|
50
|
|
|
24
|
$self->{__path} = delete $args{path} || q{}; |
208
|
4
|
|
|
|
|
6
|
$self->{__started} = 0; |
209
|
4
|
|
|
|
|
10
|
$self->{__method_table} = {}; |
210
|
4
|
|
|
|
|
8
|
$self->{__requests} = 0; |
211
|
4
|
|
50
|
|
|
21
|
$self->{__auto_methods} = delete $args{auto_methods} || 0; |
212
|
4
|
|
50
|
|
|
18
|
$self->{__auto_updates} = delete $args{auto_updates} || 0; |
213
|
4
|
|
50
|
|
|
19
|
$self->{__debug} = delete $args{debug} || 0; |
214
|
4
|
|
50
|
|
|
18
|
$self->{__xpl_path} = delete $args{xpl_path} || []; |
215
|
4
|
|
50
|
|
|
20
|
$self->{__timeout} = delete $args{timeout} || 10; |
216
|
|
|
|
|
|
|
$self->{__parser} = RPC::XML::ParserFactory->new( |
217
|
4
|
50
|
|
|
|
38
|
$args{parser} ? @{delete $args{parser}} : () |
|
0
|
|
|
|
|
0
|
|
218
|
|
|
|
|
|
|
); |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# Add the basic paths (content of @XPL_PATH) to our local XPL path |
221
|
4
|
|
|
|
|
7
|
push @{$self->{__xpl_path}}, @XPL_PATH; |
|
4
|
|
|
|
|
17
|
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# Set up the default methods unless requested not to |
224
|
4
|
100
|
|
|
|
12
|
if (! delete $args{no_default}) |
225
|
|
|
|
|
|
|
{ |
226
|
1
|
|
|
|
|
3
|
$self->add_default_methods; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# Compression support |
230
|
3
|
50
|
|
|
|
7
|
if (delete $args{no_compress}) |
231
|
|
|
|
|
|
|
{ |
232
|
0
|
|
|
|
|
0
|
$self->{__compress} = q{}; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
else |
235
|
|
|
|
|
|
|
{ |
236
|
3
|
|
|
|
|
8
|
$self->{__compress} = $COMPRESSION_AVAILABLE; |
237
|
|
|
|
|
|
|
# Add some more headers to the default response object for compression. |
238
|
|
|
|
|
|
|
# It looks wasteful to keep using the hash key, but it makes it easier |
239
|
|
|
|
|
|
|
# to change the string in just one place (above) if I have to. |
240
|
3
|
50
|
|
|
|
11
|
if ($self->{__compress}) |
241
|
|
|
|
|
|
|
{ |
242
|
3
|
|
|
|
|
19
|
$resp->header(Accept_Encoding => $self->{__compress}); |
243
|
|
|
|
|
|
|
} |
244
|
3
|
|
50
|
|
|
120
|
$self->{__compress_thresh} = delete $args{compress_thresh} || 4096; |
245
|
|
|
|
|
|
|
# Yes, I know this is redundant. It's for future expansion/flexibility. |
246
|
|
|
|
|
|
|
$self->{__compress_re} = |
247
|
3
|
50
|
|
|
|
44
|
$self->{__compress} ? qr/$self->{__compress}/ : qr/deflate/; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# Parameters to control the point at which messages are shunted to temp |
251
|
|
|
|
|
|
|
# files due to size, and where to home the temp files. Start with a size |
252
|
|
|
|
|
|
|
# threshhold of 1Meg and no specific dir (which will fall-through to the |
253
|
|
|
|
|
|
|
# tmpdir() method of File::Spec). |
254
|
|
|
|
|
|
|
$self->{__message_file_thresh} = delete $args{message_file_thresh} || |
255
|
3
|
|
50
|
|
|
18
|
1_048_576; |
256
|
3
|
|
50
|
|
|
13
|
$self->{__message_temp_dir} = delete $args{message_temp_dir} || q{}; |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# Set up the table of response codes/messages that will be used when the |
259
|
|
|
|
|
|
|
# server is sending a controlled error message to a client (as opposed to |
260
|
|
|
|
|
|
|
# something HTTP-level that is less within our control). |
261
|
3
|
|
|
|
|
5
|
$self->{__fault_table} = {}; |
262
|
3
|
|
|
|
|
11
|
for my $fault (keys %FAULT_TABLE) |
263
|
|
|
|
|
|
|
{ |
264
|
12
|
|
|
|
|
11
|
$self->{__fault_table}->{$fault} = [ @{$FAULT_TABLE{$fault}} ]; |
|
12
|
|
|
|
|
26
|
|
265
|
|
|
|
|
|
|
} |
266
|
3
|
50
|
|
|
|
10
|
if ($args{fault_code_base}) |
267
|
|
|
|
|
|
|
{ |
268
|
0
|
|
|
|
|
0
|
my $base = delete $args{fault_code_base}; |
269
|
|
|
|
|
|
|
# Apply the numerical offset to all (current) error codes |
270
|
0
|
|
|
|
|
0
|
for my $key (keys %{$self->{__fault_table}}) |
|
0
|
|
|
|
|
0
|
|
271
|
|
|
|
|
|
|
{ |
272
|
0
|
|
|
|
|
0
|
$self->{__fault_table}->{$key}->[0] += $base; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
} |
275
|
3
|
50
|
|
|
|
7
|
if ($args{fault_table}) |
276
|
|
|
|
|
|
|
{ |
277
|
0
|
|
|
|
|
0
|
my $local_table = delete $args{fault_table}; |
278
|
|
|
|
|
|
|
# Merge any data from this table into the object's fault-table |
279
|
0
|
|
|
|
|
0
|
for my $key (keys %{$local_table}) |
|
0
|
|
|
|
|
0
|
|
280
|
|
|
|
|
|
|
{ |
281
|
|
|
|
|
|
|
$self->{__fault_table}->{$key} = (ref $local_table->{$key}) ? |
282
|
0
|
0
|
|
|
|
0
|
[ @{$local_table->{$key}} ] : $local_table->{$key}; |
|
0
|
|
|
|
|
0
|
|
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Copy the remaining args over untouched |
287
|
3
|
|
|
|
|
8
|
for (keys %args) |
288
|
|
|
|
|
|
|
{ |
289
|
0
|
|
|
|
|
0
|
$self->{$_} = $args{$_}; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
3
|
|
|
|
|
23
|
return $self; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# Most of these tiny subs are accessors to the internal hash keys. They not |
296
|
|
|
|
|
|
|
# only control access to the internals, they ease sub-classing. |
297
|
|
|
|
|
|
|
|
298
|
6
|
|
|
6
|
1
|
548
|
sub version { return $VERSION } |
299
|
|
|
|
|
|
|
|
300
|
1
|
|
|
1
|
1
|
4
|
sub INSTALL_DIR { return $INSTALL_DIR } |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub url |
303
|
|
|
|
|
|
|
{ |
304
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
305
|
|
|
|
|
|
|
|
306
|
1
|
|
|
|
|
1
|
my $host; |
307
|
|
|
|
|
|
|
|
308
|
1
|
50
|
|
|
|
4
|
if ($self->{__daemon}) |
309
|
|
|
|
|
|
|
{ |
310
|
0
|
|
|
|
|
0
|
return $self->{__daemon}->url; |
311
|
|
|
|
|
|
|
} |
312
|
1
|
50
|
|
|
|
3
|
if (! ($host = $self->host)) |
313
|
|
|
|
|
|
|
{ |
314
|
1
|
|
|
|
|
3
|
return; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
0
|
|
|
|
|
0
|
my $path = $self->path; |
318
|
0
|
|
|
|
|
0
|
my $port = $self->port; |
319
|
0
|
0
|
|
|
|
0
|
if ($port == 443) |
|
|
0
|
|
|
|
|
|
320
|
|
|
|
|
|
|
{ |
321
|
0
|
|
|
|
|
0
|
return "https://$host$path"; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
elsif ($port == 80) |
324
|
|
|
|
|
|
|
{ |
325
|
0
|
|
|
|
|
0
|
return "http://$host$path"; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
else |
328
|
|
|
|
|
|
|
{ |
329
|
0
|
|
|
|
|
0
|
return "http://$host:$port$path"; |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub product_tokens |
334
|
|
|
|
|
|
|
{ |
335
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
336
|
|
|
|
|
|
|
|
337
|
1
|
|
|
|
|
1
|
my $class = ref $self; |
338
|
1
|
|
33
|
|
|
4
|
$class ||= $self; |
339
|
1
|
|
|
|
|
2
|
return sprintf '%s/%s', $class, $self->version; |
340
|
|
|
|
|
|
|
} |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# This fetches/sets the internal "started" timestamp. Unlike the other |
343
|
|
|
|
|
|
|
# plain-but-mutable attributes, this isn't set to the passed-value but |
344
|
|
|
|
|
|
|
# rather a non-null argument sets it from the current time. |
345
|
|
|
|
|
|
|
sub started |
346
|
|
|
|
|
|
|
{ |
347
|
2
|
|
|
2
|
1
|
8
|
my ($self, $set_started) = @_; |
348
|
|
|
|
|
|
|
|
349
|
2
|
|
50
|
|
|
26
|
my $old = $self->{__started} || 0; |
350
|
2
|
100
|
|
|
|
9
|
if ($set_started) |
351
|
|
|
|
|
|
|
{ |
352
|
1
|
|
|
|
|
9
|
$self->{__started} = time; |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
2
|
|
|
|
|
9
|
return $old; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
BEGIN |
359
|
|
|
|
|
|
|
{ |
360
|
8
|
|
|
8
|
|
47
|
no strict 'refs'; ## no critic (ProhibitNoStrict) |
|
8
|
|
|
|
|
9
|
|
|
8
|
|
|
|
|
930
|
|
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
# These are mutable member values for which the logic only differs in |
363
|
|
|
|
|
|
|
# the name of the field to modify: |
364
|
8
|
|
|
8
|
|
15
|
for my $method (qw(compress_thresh message_file_thresh message_temp_dir)) |
365
|
|
|
|
|
|
|
{ |
366
|
24
|
|
|
|
|
78
|
*{$method} = sub { |
367
|
0
|
|
|
0
|
|
0
|
my ($self, $value) = @_; |
368
|
|
|
|
|
|
|
|
369
|
0
|
|
|
|
|
0
|
my $old = $self->{"__$method"}; |
370
|
0
|
0
|
|
|
|
0
|
if (defined $value) |
371
|
|
|
|
|
|
|
{ |
372
|
0
|
|
|
|
|
0
|
$self->{"__$method"} = $value; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
0
|
|
|
|
|
0
|
$old; |
376
|
|
|
|
|
|
|
} |
377
|
24
|
|
|
|
|
84
|
} |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# These are immutable member values, so this simple block applies to all |
380
|
8
|
|
|
|
|
19
|
for my $method (qw(path host port requests response compress compress_re |
381
|
|
|
|
|
|
|
parser)) |
382
|
|
|
|
|
|
|
{ |
383
|
64
|
|
|
6
|
|
8801
|
*{$method} = sub { shift->{"__$method"} } |
|
6
|
|
|
|
|
414
|
|
384
|
64
|
|
|
|
|
156
|
} |
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# Get/set the search path for XPL files |
388
|
|
|
|
|
|
|
sub xpl_path |
389
|
|
|
|
|
|
|
{ |
390
|
1
|
|
|
1
|
1
|
2
|
my ($self, $path) = @_; |
391
|
1
|
|
|
|
|
2
|
my $ret = $self->{__xpl_path}; |
392
|
|
|
|
|
|
|
|
393
|
1
|
50
|
33
|
|
|
4
|
if ($path && ref $path eq 'ARRAY') |
394
|
|
|
|
|
|
|
{ |
395
|
0
|
|
|
|
|
0
|
$self->{__xpl_path} = $path; |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
|
398
|
1
|
|
|
|
|
2
|
return $ret; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
############################################################################### |
402
|
|
|
|
|
|
|
# |
403
|
|
|
|
|
|
|
# Sub Name: add_method |
404
|
|
|
|
|
|
|
# |
405
|
|
|
|
|
|
|
# Description: Add a funtion-to-method mapping to the server object. |
406
|
|
|
|
|
|
|
# |
407
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
408
|
|
|
|
|
|
|
# $self in ref Object to add to |
409
|
|
|
|
|
|
|
# $meth in scalar Hash ref of data or file name |
410
|
|
|
|
|
|
|
# |
411
|
|
|
|
|
|
|
# Globals: %CLASS_MAP |
412
|
|
|
|
|
|
|
# |
413
|
|
|
|
|
|
|
# Returns: Success: $self |
414
|
|
|
|
|
|
|
# Failure: error string |
415
|
|
|
|
|
|
|
# |
416
|
|
|
|
|
|
|
############################################################################### |
417
|
|
|
|
|
|
|
sub add_method |
418
|
|
|
|
|
|
|
{ |
419
|
3
|
|
|
3
|
1
|
1035
|
my ($self, $meth) = @_; |
420
|
|
|
|
|
|
|
|
421
|
3
|
|
|
|
|
9
|
my $me = ref($self) . '::add_method'; |
422
|
|
|
|
|
|
|
|
423
|
3
|
100
|
0
|
|
|
13
|
if (! ref $meth) |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
424
|
|
|
|
|
|
|
{ |
425
|
1
|
|
|
|
|
4
|
my $val = $self->method_from_file($meth); |
426
|
0
|
0
|
|
|
|
0
|
if (! ref $val) |
427
|
|
|
|
|
|
|
{ |
428
|
0
|
|
|
|
|
0
|
return "$me: Error loading from file $meth: $val"; |
429
|
|
|
|
|
|
|
} |
430
|
|
|
|
|
|
|
else |
431
|
|
|
|
|
|
|
{ |
432
|
0
|
|
|
|
|
0
|
$meth = $val; |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
elsif (ref $meth eq 'HASH') |
436
|
|
|
|
|
|
|
{ |
437
|
|
|
|
|
|
|
# Make a copy of the contents of $meth, so we don't make permanent |
438
|
|
|
|
|
|
|
# changes: |
439
|
2
|
|
|
|
|
2
|
my %meth_copy = map { $_ => $meth->{$_} } (keys %{$meth}); |
|
6
|
|
|
|
|
12
|
|
|
2
|
|
|
|
|
4
|
|
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
# If the type of this method is not set, default to "method". The |
442
|
|
|
|
|
|
|
# add_procedure and add_function calls should set this as needed. |
443
|
2
|
|
50
|
|
|
10
|
my $type = delete $meth_copy{type} || 'method'; |
444
|
|
|
|
|
|
|
|
445
|
2
|
50
|
|
|
|
8
|
if (! (my $class = $CLASS_MAP{lc $type})) |
446
|
|
|
|
|
|
|
{ |
447
|
0
|
|
|
|
|
0
|
return "$me: Unknown type: $type"; |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
else |
450
|
|
|
|
|
|
|
{ |
451
|
2
|
|
|
|
|
20
|
$meth = $class->new(\%meth_copy); |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
elsif (! (blessed $meth and $meth->isa('RPC::XML::Procedure'))) |
455
|
|
|
|
|
|
|
{ |
456
|
0
|
|
|
|
|
0
|
return "$me: Method argument must be a file name, a hash " . |
457
|
|
|
|
|
|
|
'reference or an object derived from RPC::XML::Procedure'; |
458
|
|
|
|
|
|
|
} |
459
|
|
|
|
|
|
|
|
460
|
2
|
|
|
|
|
10
|
$self->{__method_table}->{$meth->name} = $meth; |
461
|
|
|
|
|
|
|
|
462
|
2
|
|
|
|
|
4
|
return $self; |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
############################################################################### |
466
|
|
|
|
|
|
|
# |
467
|
|
|
|
|
|
|
# Sub Name: add_procedure |
468
|
|
|
|
|
|
|
# |
469
|
|
|
|
|
|
|
# Description: This filters through to add_method, but if the passed-in |
470
|
|
|
|
|
|
|
# value is a hash reference forces the "type" to be |
471
|
|
|
|
|
|
|
# "procedure". |
472
|
|
|
|
|
|
|
# |
473
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
474
|
|
|
|
|
|
|
# $self in ref Object reference |
475
|
|
|
|
|
|
|
# $meth in scalar Procedure to add |
476
|
|
|
|
|
|
|
# |
477
|
|
|
|
|
|
|
# Returns: threads through to add_method |
478
|
|
|
|
|
|
|
# |
479
|
|
|
|
|
|
|
############################################################################### |
480
|
|
|
|
|
|
|
sub add_procedure |
481
|
|
|
|
|
|
|
{ |
482
|
0
|
|
|
0
|
1
|
0
|
my ($self, $meth) = @_; |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# Anything else but a hash-reference goes through unaltered |
485
|
0
|
0
|
|
|
|
0
|
if (ref($meth) eq 'HASH') |
486
|
|
|
|
|
|
|
{ |
487
|
0
|
|
|
|
|
0
|
$meth->{type} = 'procedure'; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
0
|
|
|
|
|
0
|
return $self->add_method($meth); |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
############################################################################### |
494
|
|
|
|
|
|
|
# |
495
|
|
|
|
|
|
|
# Sub Name: add_function |
496
|
|
|
|
|
|
|
# |
497
|
|
|
|
|
|
|
# Description: This filters through to add_method, but if the passed-in |
498
|
|
|
|
|
|
|
# value is a hash reference forces the "type" to be |
499
|
|
|
|
|
|
|
# "function". |
500
|
|
|
|
|
|
|
# |
501
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
502
|
|
|
|
|
|
|
# $self in ref Object reference |
503
|
|
|
|
|
|
|
# $meth in scalar Procedure to add |
504
|
|
|
|
|
|
|
# |
505
|
|
|
|
|
|
|
# Returns: threads through to add_method |
506
|
|
|
|
|
|
|
# |
507
|
|
|
|
|
|
|
############################################################################### |
508
|
|
|
|
|
|
|
sub add_function |
509
|
|
|
|
|
|
|
{ |
510
|
0
|
|
|
0
|
1
|
0
|
my ($self, $meth) = @_; |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# Anything else but a hash-reference goes through unaltered |
513
|
0
|
0
|
|
|
|
0
|
if (ref($meth) eq 'HASH') |
514
|
|
|
|
|
|
|
{ |
515
|
0
|
|
|
|
|
0
|
$meth->{type} = 'function'; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
0
|
|
|
|
|
0
|
return $self->add_method($meth); |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
############################################################################### |
522
|
|
|
|
|
|
|
# |
523
|
|
|
|
|
|
|
# Sub Name: method_from_file |
524
|
|
|
|
|
|
|
# |
525
|
|
|
|
|
|
|
# Description: Create a RPC::XML::Procedure (or ::Method) object from the |
526
|
|
|
|
|
|
|
# passed-in file name, using the object's search path if the |
527
|
|
|
|
|
|
|
# name is not already absolute. |
528
|
|
|
|
|
|
|
# |
529
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
530
|
|
|
|
|
|
|
# $self in ref Object of this class |
531
|
|
|
|
|
|
|
# $file in scalar Name of file to load |
532
|
|
|
|
|
|
|
# |
533
|
|
|
|
|
|
|
# Returns: Success: Method-object reference |
534
|
|
|
|
|
|
|
# Failure: error message |
535
|
|
|
|
|
|
|
# |
536
|
|
|
|
|
|
|
############################################################################### |
537
|
|
|
|
|
|
|
sub method_from_file |
538
|
|
|
|
|
|
|
{ |
539
|
2
|
|
|
2
|
0
|
386
|
my ($self, $file) = @_; |
540
|
|
|
|
|
|
|
|
541
|
2
|
100
|
|
|
|
22
|
if (! File::Spec->file_name_is_absolute($file)) |
542
|
|
|
|
|
|
|
{ |
543
|
1
|
|
|
|
|
1
|
my $path; |
544
|
1
|
|
|
|
|
2
|
for my $dir (@{$self->xpl_path}) |
|
1
|
|
|
|
|
3
|
|
545
|
|
|
|
|
|
|
{ |
546
|
2
|
|
|
|
|
18
|
$path = File::Spec->catfile($dir, $file); |
547
|
2
|
50
|
|
|
|
55
|
if (-f $path) |
548
|
|
|
|
|
|
|
{ |
549
|
0
|
|
|
|
|
0
|
$file = File::Spec->canonpath($path); |
550
|
0
|
|
|
|
|
0
|
last; |
551
|
|
|
|
|
|
|
} |
552
|
|
|
|
|
|
|
} |
553
|
|
|
|
|
|
|
} |
554
|
|
|
|
|
|
|
# Just in case it still didn't appear in the path, we really want an |
555
|
|
|
|
|
|
|
# absolute path: |
556
|
2
|
100
|
|
|
|
10
|
if (! File::Spec->file_name_is_absolute($file)) |
557
|
|
|
|
|
|
|
{ |
558
|
1
|
|
|
|
|
16
|
$file = File::Spec->rel2abs($file); |
559
|
|
|
|
|
|
|
} |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
# When reading a XPL file, RPC::XML::Procedure->new() acts sort of like a |
562
|
|
|
|
|
|
|
# factory constructor, returning the type of object the XPL file specifies |
563
|
|
|
|
|
|
|
# even when that isn't RPC::XML::Procedure. |
564
|
2
|
|
|
|
|
18
|
return RPC::XML::Procedure->new($file); |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
############################################################################### |
568
|
|
|
|
|
|
|
# |
569
|
|
|
|
|
|
|
# Sub Name: get_method |
570
|
|
|
|
|
|
|
# |
571
|
|
|
|
|
|
|
# Description: Get the current binding for the remote-side method $name. |
572
|
|
|
|
|
|
|
# Returns undef if the method is not defined for the server |
573
|
|
|
|
|
|
|
# instance. |
574
|
|
|
|
|
|
|
# |
575
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
576
|
|
|
|
|
|
|
# $self in ref Class instance |
577
|
|
|
|
|
|
|
# $name in scalar Name of the method being looked |
578
|
|
|
|
|
|
|
# up |
579
|
|
|
|
|
|
|
# |
580
|
|
|
|
|
|
|
# Returns: Success: Method-class reference |
581
|
|
|
|
|
|
|
# Failure: error string |
582
|
|
|
|
|
|
|
# |
583
|
|
|
|
|
|
|
############################################################################### |
584
|
|
|
|
|
|
|
sub get_method |
585
|
|
|
|
|
|
|
{ |
586
|
0
|
|
|
0
|
1
|
0
|
my ($self, $name) = @_; |
587
|
|
|
|
|
|
|
|
588
|
0
|
|
|
|
|
0
|
my $meth = $self->{__method_table}->{$name}; |
589
|
0
|
0
|
|
|
|
0
|
if (! defined $meth) |
590
|
|
|
|
|
|
|
{ |
591
|
0
|
0
|
|
|
|
0
|
if ($self->{__auto_methods}) |
592
|
|
|
|
|
|
|
{ |
593
|
|
|
|
|
|
|
# Try to load this dynamically on the fly, from any of the dirs |
594
|
|
|
|
|
|
|
# that are in this object's @xpl_path |
595
|
0
|
|
|
|
|
0
|
(my $loadname = $name) =~ s/^system[.]//; |
596
|
0
|
|
|
|
|
0
|
$self->add_method("$loadname.xpl"); |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
# If method is still not in the table, we were unable to load it |
599
|
0
|
0
|
|
|
|
0
|
if (! ($meth = $self->{__method_table}->{$name})) |
600
|
|
|
|
|
|
|
{ |
601
|
0
|
|
|
|
|
0
|
return "Unknown method: $name"; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
# Check the mod-time of the file the method came from, if the test is on |
605
|
0
|
0
|
0
|
|
|
0
|
if ($self->{__auto_updates} && |
|
|
|
0
|
|
|
|
|
606
|
|
|
|
|
|
|
$meth->{file} && |
607
|
|
|
|
|
|
|
($meth->{mtime} < (stat $meth->{file})[9])) |
608
|
|
|
|
|
|
|
{ |
609
|
0
|
|
|
|
|
0
|
my $ret = $meth->reload; |
610
|
0
|
0
|
|
|
|
0
|
if (! ref $ret) |
611
|
|
|
|
|
|
|
{ |
612
|
0
|
|
|
|
|
0
|
return "Reload of method $name failed: $ret"; |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
0
|
|
|
|
|
0
|
return $meth; |
617
|
|
|
|
|
|
|
} |
618
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
# For name-symmetry: |
620
|
|
|
|
|
|
|
*get_procedure = *get_function = \&get_method; |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
############################################################################### |
623
|
|
|
|
|
|
|
# |
624
|
|
|
|
|
|
|
# Sub Name: server_loop |
625
|
|
|
|
|
|
|
# |
626
|
|
|
|
|
|
|
# Description: Enter a server-loop situation, using the accept() loop of |
627
|
|
|
|
|
|
|
# HTTP::Daemon if $self has such an object, or falling back |
628
|
|
|
|
|
|
|
# Net::Server otherwise. |
629
|
|
|
|
|
|
|
# |
630
|
|
|
|
|
|
|
# The critic disabling is because we may manipulate @_ |
631
|
|
|
|
|
|
|
# when using Net::Server. |
632
|
|
|
|
|
|
|
# |
633
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
634
|
|
|
|
|
|
|
# $self in ref Object of this class |
635
|
|
|
|
|
|
|
# %args in hash Additional parameters to set up |
636
|
|
|
|
|
|
|
# before calling the superclass |
637
|
|
|
|
|
|
|
# Run method |
638
|
|
|
|
|
|
|
# |
639
|
|
|
|
|
|
|
# Returns: string if error, otherwise void |
640
|
|
|
|
|
|
|
# |
641
|
|
|
|
|
|
|
############################################################################### |
642
|
|
|
|
|
|
|
sub server_loop ## no critic (RequireArgUnpacking,ProhibitExcessComplexity) |
643
|
|
|
|
|
|
|
{ |
644
|
1
|
|
|
1
|
1
|
1425
|
my $self = shift; |
645
|
|
|
|
|
|
|
|
646
|
1
|
50
|
|
|
|
31
|
if ($self->{__daemon}) |
647
|
|
|
|
|
|
|
{ |
648
|
1
|
|
|
|
|
8
|
my ($conn, $req, $resp, $reqxml, $respxml, $exit_now, $timeout, |
649
|
|
|
|
|
|
|
$eval_return); |
650
|
|
|
|
|
|
|
|
651
|
1
|
|
|
|
|
28
|
my %args = @_; |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
# Localize and set the signal handler as an exit route |
654
|
1
|
|
|
|
|
7
|
my @exit_signals; |
655
|
|
|
|
|
|
|
|
656
|
1
|
50
|
33
|
|
|
24
|
if (exists $args{signal} and $args{signal} ne 'NONE') |
657
|
|
|
|
|
|
|
{ |
658
|
|
|
|
|
|
|
@exit_signals = |
659
|
0
|
0
|
|
|
|
0
|
(ref $args{signal}) ? @{$args{signal}} : $args{signal}; |
|
0
|
|
|
|
|
0
|
|
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
else |
662
|
|
|
|
|
|
|
{ |
663
|
1
|
|
|
|
|
10
|
push @exit_signals, 'INT'; |
664
|
|
|
|
|
|
|
} |
665
|
|
|
|
|
|
|
|
666
|
1
|
|
|
0
|
|
89
|
local @SIG{@exit_signals} = (sub { $exit_now++ }) x @exit_signals; |
|
0
|
|
|
|
|
0
|
|
667
|
|
|
|
|
|
|
|
668
|
1
|
|
|
|
|
38
|
$self->started('set'); |
669
|
1
|
|
|
|
|
1
|
$exit_now = 0; |
670
|
1
|
|
|
|
|
66
|
$timeout = $self->{__daemon}->timeout(1); |
671
|
1
|
|
|
|
|
33
|
while (! $exit_now) |
672
|
|
|
|
|
|
|
{ |
673
|
1
|
|
|
|
|
35
|
$conn = $self->{__daemon}->accept; |
674
|
|
|
|
|
|
|
|
675
|
1
|
50
|
|
|
|
2687
|
if ($exit_now) |
676
|
|
|
|
|
|
|
{ |
677
|
0
|
|
|
|
|
0
|
last; |
678
|
|
|
|
|
|
|
} |
679
|
1
|
50
|
|
|
|
9
|
if (! $conn) |
680
|
|
|
|
|
|
|
{ |
681
|
0
|
|
|
|
|
0
|
next; |
682
|
|
|
|
|
|
|
} |
683
|
1
|
|
|
|
|
14
|
$conn->timeout($self->timeout); |
684
|
1
|
|
|
|
|
13
|
$self->process_request($conn); |
685
|
|
|
|
|
|
|
|
686
|
0
|
|
|
|
|
0
|
$eval_return = eval { |
687
|
0
|
|
|
0
|
|
0
|
local $SIG{PIPE} = sub { die "server_loop: Caught SIGPIPE\n"; }; |
|
0
|
|
|
|
|
0
|
|
688
|
0
|
|
|
|
|
0
|
$conn->close; |
689
|
0
|
|
|
|
|
0
|
1; |
690
|
|
|
|
|
|
|
}; |
691
|
0
|
0
|
0
|
|
|
0
|
if ((! $eval_return) && $@) |
692
|
|
|
|
|
|
|
{ |
693
|
0
|
|
|
|
|
0
|
warn "Cannot close connection: $@\n"; |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
|
696
|
0
|
|
|
|
|
0
|
undef $conn; # Free up any lingering resources |
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
|
699
|
0
|
0
|
|
|
|
0
|
if (defined $timeout) |
700
|
|
|
|
|
|
|
{ |
701
|
0
|
|
|
|
|
0
|
$self->{__daemon}->timeout($timeout); |
702
|
|
|
|
|
|
|
} |
703
|
|
|
|
|
|
|
} |
704
|
|
|
|
|
|
|
else |
705
|
|
|
|
|
|
|
{ |
706
|
|
|
|
|
|
|
# This is the Net::Server block, but for now HTTP::Daemon is needed |
707
|
|
|
|
|
|
|
# for the code that converts socket data to a HTTP::Request object |
708
|
0
|
|
|
|
|
0
|
require HTTP::Daemon; |
709
|
|
|
|
|
|
|
|
710
|
0
|
|
|
|
|
0
|
my $conf_file_flag = 0; |
711
|
0
|
|
|
|
|
0
|
my $port_flag = 0; |
712
|
0
|
|
|
|
|
0
|
my $host_flag = 0; |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
# Disable critic on the C-style for-loop because we need to step by |
715
|
|
|
|
|
|
|
# 2 as we check for Net::Server arguments... |
716
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i < @_; $i += 2) ## no critic (ProhibitCStyleForLoops) |
717
|
|
|
|
|
|
|
{ |
718
|
0
|
0
|
|
|
|
0
|
if ($_[$i] eq 'conf_file') { $conf_file_flag = 1; } |
|
0
|
|
|
|
|
0
|
|
719
|
0
|
0
|
|
|
|
0
|
if ($_[$i] eq 'port') { $port_flag = 1; } |
|
0
|
|
|
|
|
0
|
|
720
|
0
|
0
|
|
|
|
0
|
if ($_[$i] eq 'host') { $host_flag = 1; } |
|
0
|
|
|
|
|
0
|
|
721
|
|
|
|
|
|
|
} |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
# An explicitly-given conf-file trumps any specified at creation |
724
|
0
|
0
|
0
|
|
|
0
|
if (exists($self->{conf_file}) and (!$conf_file_flag)) |
725
|
|
|
|
|
|
|
{ |
726
|
0
|
|
|
|
|
0
|
push @_, 'conf_file', $self->{conf_file}; |
727
|
0
|
|
|
|
|
0
|
$conf_file_flag = 1; |
728
|
|
|
|
|
|
|
} |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
# Don't do this next part if they've already given a port, or are |
731
|
|
|
|
|
|
|
# pointing to a config file: |
732
|
0
|
0
|
0
|
|
|
0
|
if (! ($conf_file_flag || $port_flag)) |
733
|
|
|
|
|
|
|
{ |
734
|
0
|
|
0
|
|
|
0
|
push @_, 'port', $self->{port} || $self->port || 9000; |
735
|
0
|
|
0
|
|
|
0
|
push @_, 'host', $self->{host} || $self->host || q{*}; |
736
|
|
|
|
|
|
|
} |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
# Try to load the Net::Server::MultiType module |
739
|
0
|
0
|
|
|
|
0
|
if (! eval { require Net::Server::MultiType; 1; }) |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
740
|
|
|
|
|
|
|
{ |
741
|
0
|
0
|
|
|
|
0
|
if ($@) |
742
|
|
|
|
|
|
|
{ |
743
|
0
|
|
|
|
|
0
|
return ref($self) . |
744
|
|
|
|
|
|
|
"::server_loop: Error loading Net::Server::MultiType: $@"; |
745
|
|
|
|
|
|
|
} |
746
|
|
|
|
|
|
|
} |
747
|
0
|
|
|
|
|
0
|
unshift @RPC::XML::Server::ISA, 'Net::Server::MultiType'; |
748
|
|
|
|
|
|
|
|
749
|
0
|
|
|
|
|
0
|
$self->started('set'); |
750
|
|
|
|
|
|
|
# ...and we're off! |
751
|
0
|
|
|
|
|
0
|
$self->run(@_); |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
|
754
|
0
|
|
|
|
|
0
|
return; |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
############################################################################### |
758
|
|
|
|
|
|
|
# |
759
|
|
|
|
|
|
|
# Sub Name: post_configure_loop |
760
|
|
|
|
|
|
|
# |
761
|
|
|
|
|
|
|
# Description: Called by the Net::Server classes after all the config |
762
|
|
|
|
|
|
|
# steps have been done and merged. |
763
|
|
|
|
|
|
|
# |
764
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
765
|
|
|
|
|
|
|
# $self in ref Class object |
766
|
|
|
|
|
|
|
# |
767
|
|
|
|
|
|
|
# Returns: $self |
768
|
|
|
|
|
|
|
# |
769
|
|
|
|
|
|
|
############################################################################### |
770
|
|
|
|
|
|
|
sub post_configure_hook |
771
|
|
|
|
|
|
|
{ |
772
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
773
|
|
|
|
|
|
|
|
774
|
0
|
|
|
|
|
0
|
$self->{__host} = $self->{server}->{host}; |
775
|
0
|
|
|
|
|
0
|
$self->{__port} = $self->{server}->{port}; |
776
|
|
|
|
|
|
|
|
777
|
0
|
|
|
|
|
0
|
return $self; |
778
|
|
|
|
|
|
|
} |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
############################################################################### |
781
|
|
|
|
|
|
|
# |
782
|
|
|
|
|
|
|
# Sub Name: pre_loop_hook |
783
|
|
|
|
|
|
|
# |
784
|
|
|
|
|
|
|
# Description: Called by Net::Server classes after the post_bind method, |
785
|
|
|
|
|
|
|
# but before the socket-accept loop starts. |
786
|
|
|
|
|
|
|
# |
787
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
788
|
|
|
|
|
|
|
# $self in ref Object instance |
789
|
|
|
|
|
|
|
# |
790
|
|
|
|
|
|
|
# Returns: $self |
791
|
|
|
|
|
|
|
# |
792
|
|
|
|
|
|
|
############################################################################### |
793
|
|
|
|
|
|
|
sub pre_loop_hook |
794
|
|
|
|
|
|
|
{ |
795
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
# We have to disable the __DIE__ handler for the sake of XML::Parser::Expat |
798
|
0
|
|
|
|
|
0
|
$SIG{__DIE__} = q{}; ## no critic (RequireLocalizedPunctuationVars) |
799
|
|
|
|
|
|
|
|
800
|
0
|
|
|
|
|
0
|
return $self; |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
|
803
|
|
|
|
|
|
|
############################################################################### |
804
|
|
|
|
|
|
|
# |
805
|
|
|
|
|
|
|
# Sub Name: process_request |
806
|
|
|
|
|
|
|
# |
807
|
|
|
|
|
|
|
# Description: This is provided for the case when we run as a subclass |
808
|
|
|
|
|
|
|
# of Net::Server. |
809
|
|
|
|
|
|
|
# |
810
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
811
|
|
|
|
|
|
|
# $self in ref This class object |
812
|
|
|
|
|
|
|
# $conn in ref If present, it's a connection |
813
|
|
|
|
|
|
|
# object from HTTP::Daemon |
814
|
|
|
|
|
|
|
# |
815
|
|
|
|
|
|
|
# Returns: void |
816
|
|
|
|
|
|
|
# |
817
|
|
|
|
|
|
|
############################################################################### |
818
|
|
|
|
|
|
|
sub process_request ## no critic (ProhibitExcessComplexity) |
819
|
|
|
|
|
|
|
{ |
820
|
1
|
|
|
1
|
0
|
12
|
my $self = shift; |
821
|
1
|
|
|
|
|
2
|
my $conn = shift; |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
my ( |
824
|
1
|
|
|
|
|
1
|
$req, $reqxml, $resp, $respxml, $do_compress, |
825
|
|
|
|
|
|
|
$parser, $com_engine, $length, $read, $buf, |
826
|
|
|
|
|
|
|
$resp_fh, $tmpdir, $peeraddr, $peerhost, $peerport |
827
|
|
|
|
|
|
|
); |
828
|
|
|
|
|
|
|
|
829
|
1
|
|
|
|
|
10
|
my $me = ref($self) . '::process_request'; |
830
|
1
|
50
|
|
|
|
7
|
if (! $conn) |
831
|
|
|
|
|
|
|
{ |
832
|
|
|
|
|
|
|
# Maintain compatibility with Net::Server 0.99, which does not pass |
833
|
|
|
|
|
|
|
# the connection object at all: |
834
|
0
|
|
|
|
|
0
|
$conn = $self->{server}->{client}; |
835
|
|
|
|
|
|
|
} |
836
|
1
|
50
|
|
|
|
10
|
if (ref($conn) =~ /^Net::Server::Proto/) |
837
|
|
|
|
|
|
|
{ |
838
|
0
|
|
|
|
|
0
|
bless $conn, 'HTTP::Daemon::ClientConn'; |
839
|
0
|
|
|
|
|
0
|
${*{$conn}}{'httpd_daemon'} = $self; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
840
|
|
|
|
|
|
|
|
841
|
0
|
0
|
0
|
|
|
0
|
if ($IO::Socket::SSL::VERSION && |
842
|
|
|
|
|
|
|
$RPC::XML::Server::IO_SOCKET_SSL_HACK_NEEDED) |
843
|
|
|
|
|
|
|
{ |
844
|
8
|
|
|
8
|
|
41
|
no strict 'vars'; ## no critic (ProhibitNoStrict) |
|
8
|
|
|
|
|
9
|
|
|
8
|
|
|
|
|
15659
|
|
845
|
|
|
|
|
|
|
# RT 43019: Don't do this if Socket6/IO::Socket::INET6 is in |
846
|
|
|
|
|
|
|
# effect, as it causes calls to unpack_sockaddr_in6 to break. |
847
|
0
|
0
|
0
|
|
|
0
|
if (! (defined $Socket6::VERSION || |
848
|
|
|
|
|
|
|
defined $IO::Socket::INET6::VERSION)) |
849
|
|
|
|
|
|
|
{ |
850
|
0
|
|
|
|
|
0
|
unshift @HTTP::Daemon::ClientConn::ISA, 'IO::Socket::SSL'; |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
|
853
|
0
|
|
|
|
|
0
|
$RPC::XML::Server::IO_SOCKET_SSL_HACK_NEEDED = 0; |
854
|
|
|
|
|
|
|
} |
855
|
|
|
|
|
|
|
} |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
# These will be attached to any and all request objects that are |
858
|
|
|
|
|
|
|
# (successfully) read from $conn. |
859
|
1
|
|
|
|
|
18
|
$peeraddr = $conn->peeraddr; |
860
|
1
|
|
|
|
|
58
|
$peerport = $conn->peerport; |
861
|
1
|
|
|
|
|
21
|
$peerhost = $conn->peerhost; |
862
|
1
|
|
33
|
|
|
42
|
while ($conn and $req = $conn->get_request('headers only')) |
863
|
|
|
|
|
|
|
{ |
864
|
1
|
50
|
|
|
|
767
|
if ($req->method eq 'HEAD') |
|
|
50
|
|
|
|
|
|
865
|
|
|
|
|
|
|
{ |
866
|
|
|
|
|
|
|
# The HEAD method will be answered with our return headers, |
867
|
|
|
|
|
|
|
# both as a means of self-identification and a verification |
868
|
|
|
|
|
|
|
# of live-status. All the headers were pre-set in the cached |
869
|
|
|
|
|
|
|
# HTTP::Response object. Also, we don't count this for stats. |
870
|
0
|
|
|
|
|
0
|
$conn->send_response($self->response); |
871
|
|
|
|
|
|
|
} |
872
|
|
|
|
|
|
|
elsif ($req->method eq 'POST') |
873
|
|
|
|
|
|
|
{ |
874
|
|
|
|
|
|
|
# Get a XML::Parser::ExpatNB object |
875
|
1
|
|
|
|
|
34
|
$parser = $self->parser->parse(); |
876
|
|
|
|
|
|
|
|
877
|
0
|
|
|
|
|
0
|
$do_compress = 0; # in case it was set for a previous response |
878
|
0
|
0
|
0
|
|
|
0
|
if (($req->content_encoding || q{}) =~ $self->compress_re) |
879
|
|
|
|
|
|
|
{ |
880
|
0
|
0
|
|
|
|
0
|
if (! $self->compress) |
881
|
|
|
|
|
|
|
{ |
882
|
0
|
|
|
|
|
0
|
$conn->send_error(RC_BAD_REQUEST, |
883
|
|
|
|
|
|
|
"$me: Compression not permitted in " . 'requests'); |
884
|
0
|
|
|
|
|
0
|
next; |
885
|
|
|
|
|
|
|
} |
886
|
|
|
|
|
|
|
|
887
|
0
|
|
|
|
|
0
|
$do_compress = 1; |
888
|
|
|
|
|
|
|
} |
889
|
|
|
|
|
|
|
|
890
|
0
|
0
|
0
|
|
|
0
|
if (($req->content_encoding || q{}) =~ /chunked/i) |
891
|
|
|
|
|
|
|
{ |
892
|
|
|
|
|
|
|
# Technically speaking, we're not supposed to honor chunked |
893
|
|
|
|
|
|
|
# transfer-encoding... |
894
|
0
|
|
|
|
|
0
|
croak "$me: 'chunked' content-encoding not (yet) supported"; |
895
|
|
|
|
|
|
|
} |
896
|
|
|
|
|
|
|
else |
897
|
|
|
|
|
|
|
{ |
898
|
0
|
|
|
|
|
0
|
$length = $req->content_length; |
899
|
0
|
0
|
|
|
|
0
|
if ($do_compress) |
900
|
|
|
|
|
|
|
{ |
901
|
|
|
|
|
|
|
# Spin up the compression engine |
902
|
0
|
0
|
|
|
|
0
|
if (! ($com_engine = Compress::Zlib::inflateInit())) |
903
|
|
|
|
|
|
|
{ |
904
|
0
|
|
|
|
|
0
|
$conn->send_error(RC_INTERNAL_SERVER_ERROR, |
905
|
|
|
|
|
|
|
"$me: Unable to initialize the " . |
906
|
|
|
|
|
|
|
'Compress::Zlib engine'); |
907
|
0
|
|
|
|
|
0
|
next; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
|
911
|
0
|
|
|
|
|
0
|
$buf = q{}; |
912
|
0
|
|
|
|
|
0
|
while ($length > 0) |
913
|
|
|
|
|
|
|
{ |
914
|
0
|
0
|
|
|
|
0
|
if ($buf = $conn->read_buffer) |
915
|
|
|
|
|
|
|
{ |
916
|
|
|
|
|
|
|
# Anything that get_request read, but didn't use, was |
917
|
|
|
|
|
|
|
# left in the read buffer. The call to sysread() should |
918
|
|
|
|
|
|
|
# NOT be made until we've emptied this source, first. |
919
|
0
|
|
|
|
|
0
|
$read = length $buf; |
920
|
0
|
|
|
|
|
0
|
$conn->read_buffer(q{}); # Clear it, now that it's read |
921
|
|
|
|
|
|
|
} |
922
|
|
|
|
|
|
|
else |
923
|
|
|
|
|
|
|
{ |
924
|
0
|
0
|
|
|
|
0
|
$read = sysread $conn, $buf, |
925
|
|
|
|
|
|
|
($length < 2048) ? $length : 2048; |
926
|
0
|
0
|
|
|
|
0
|
if (! $read) |
927
|
|
|
|
|
|
|
{ |
928
|
|
|
|
|
|
|
# Convert this print to a logging-hook call. |
929
|
|
|
|
|
|
|
# Umm, when I have real logging hooks, I mean. |
930
|
|
|
|
|
|
|
# The point is, odds are very good that $conn is |
931
|
|
|
|
|
|
|
# dead to us now, and I don't want this package |
932
|
|
|
|
|
|
|
# taking over SIGPIPE as well as the ones it |
933
|
|
|
|
|
|
|
# already monopolizes. |
934
|
|
|
|
|
|
|
#print STDERR "Error: Connection Dropped\n"; |
935
|
0
|
|
|
|
|
0
|
return; |
936
|
|
|
|
|
|
|
} |
937
|
|
|
|
|
|
|
} |
938
|
0
|
|
|
|
|
0
|
$length -= $read; |
939
|
0
|
0
|
|
|
|
0
|
if ($do_compress) |
940
|
|
|
|
|
|
|
{ |
941
|
0
|
0
|
|
|
|
0
|
if (! ($buf = $com_engine->inflate($buf))) |
942
|
|
|
|
|
|
|
{ |
943
|
0
|
|
|
|
|
0
|
$conn->send_error(RC_INTERNAL_SERVER_ERROR, |
944
|
|
|
|
|
|
|
"$me: Error inflating " . 'compressed data'); |
945
|
|
|
|
|
|
|
# This error also means that even if Keep-Alive |
946
|
|
|
|
|
|
|
# is set, we don't know how much of the stream |
947
|
|
|
|
|
|
|
# is corrupted. |
948
|
0
|
|
|
|
|
0
|
$conn->force_last_request; |
949
|
0
|
|
|
|
|
0
|
next; |
950
|
|
|
|
|
|
|
} |
951
|
|
|
|
|
|
|
} |
952
|
|
|
|
|
|
|
|
953
|
0
|
0
|
|
|
|
0
|
if (! eval { $parser->parse_more($buf); 1; }) |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
954
|
|
|
|
|
|
|
{ |
955
|
0
|
0
|
|
|
|
0
|
if ($@) |
956
|
|
|
|
|
|
|
{ |
957
|
0
|
|
|
|
|
0
|
$conn->send_error( |
958
|
|
|
|
|
|
|
RC_INTERNAL_SERVER_ERROR, |
959
|
|
|
|
|
|
|
"$me: Parse error in (compressed) " . |
960
|
|
|
|
|
|
|
"XML request (mid): $@" |
961
|
|
|
|
|
|
|
); |
962
|
|
|
|
|
|
|
# Again, the stream is likely corrupted |
963
|
0
|
|
|
|
|
0
|
$conn->force_last_request; |
964
|
0
|
|
|
|
|
0
|
next; |
965
|
|
|
|
|
|
|
} |
966
|
|
|
|
|
|
|
} |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
|
969
|
0
|
0
|
|
|
|
0
|
if (! eval { $reqxml = $parser->parse_done(); 1; }) |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
970
|
|
|
|
|
|
|
{ |
971
|
0
|
0
|
|
|
|
0
|
if ($@) |
972
|
|
|
|
|
|
|
{ |
973
|
0
|
|
|
|
|
0
|
$conn->send_error(RC_INTERNAL_SERVER_ERROR, |
974
|
|
|
|
|
|
|
"$me: Parse error in (compressed) " . |
975
|
|
|
|
|
|
|
"XML request (end): $@"); |
976
|
0
|
|
|
|
|
0
|
next; |
977
|
|
|
|
|
|
|
} |
978
|
|
|
|
|
|
|
} |
979
|
|
|
|
|
|
|
} |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
# Dispatch will always return a RPC::XML::response. |
982
|
|
|
|
|
|
|
# RT29351: If there was an error from RPC::XML::ParserFactory |
983
|
|
|
|
|
|
|
# (such as a message that didn't conform to spec), then return it |
984
|
|
|
|
|
|
|
# directly as a fault, don't have dispatch() try and handle it. |
985
|
0
|
0
|
|
|
|
0
|
if (ref $reqxml) |
986
|
|
|
|
|
|
|
{ |
987
|
|
|
|
|
|
|
# Set localized keys on $self, based on the connection info |
988
|
|
|
|
|
|
|
## no critic (ProhibitLocalVars) |
989
|
0
|
|
|
|
|
0
|
local $self->{peeraddr} = $peeraddr; |
990
|
0
|
|
|
|
|
0
|
local $self->{peerhost} = $peerhost; |
991
|
0
|
|
|
|
|
0
|
local $self->{peerport} = $peerport; |
992
|
0
|
|
|
|
|
0
|
local $self->{request} = $req; |
993
|
0
|
|
|
|
|
0
|
$respxml = $self->dispatch($reqxml); |
994
|
|
|
|
|
|
|
} |
995
|
|
|
|
|
|
|
else |
996
|
|
|
|
|
|
|
{ |
997
|
0
|
|
|
|
|
0
|
$respxml = RPC::XML::response->new( |
998
|
|
|
|
|
|
|
$self->server_fault('badxml', $reqxml)); |
999
|
|
|
|
|
|
|
} |
1000
|
|
|
|
|
|
|
|
1001
|
|
|
|
|
|
|
# Clone the pre-fab response and set headers |
1002
|
0
|
|
|
|
|
0
|
$resp = $self->response->clone; |
1003
|
|
|
|
|
|
|
# Should we apply compression to the outgoing response? |
1004
|
0
|
|
|
|
|
0
|
$do_compress = 0; # In case it was set above for incoming data |
1005
|
0
|
0
|
0
|
|
|
0
|
if ($self->compress && |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1006
|
|
|
|
|
|
|
($respxml->length > $self->compress_thresh) && |
1007
|
|
|
|
|
|
|
(($req->header('Accept-Encoding') || q{}) =~ |
1008
|
|
|
|
|
|
|
$self->compress_re)) |
1009
|
|
|
|
|
|
|
{ |
1010
|
0
|
|
|
|
|
0
|
$do_compress = 1; |
1011
|
0
|
|
|
|
|
0
|
$resp->header(Content_Encoding => $self->compress); |
1012
|
|
|
|
|
|
|
} |
1013
|
|
|
|
|
|
|
# Next step, determine the response disposition. If it is above the |
1014
|
|
|
|
|
|
|
# threshhold for a requested file cut-off, send it to a temp file |
1015
|
0
|
0
|
0
|
|
|
0
|
if ($self->message_file_thresh && |
1016
|
|
|
|
|
|
|
$self->message_file_thresh < $respxml->length) |
1017
|
|
|
|
|
|
|
{ |
1018
|
|
|
|
|
|
|
# Start by creating a temp-file |
1019
|
0
|
|
0
|
|
|
0
|
$tmpdir = $self->message_temp_dir || File::Spec->tmpdir; |
1020
|
|
|
|
|
|
|
# File::Temp->new() croaks on error |
1021
|
|
|
|
|
|
|
$resp_fh = |
1022
|
0
|
|
|
|
|
0
|
eval { File::Temp->new(UNLINK => 1, DIR => $tmpdir) }; |
|
0
|
|
|
|
|
0
|
|
1023
|
0
|
0
|
|
|
|
0
|
if (! $resp_fh) |
1024
|
|
|
|
|
|
|
{ |
1025
|
0
|
|
|
|
|
0
|
$conn->send_error( |
1026
|
|
|
|
|
|
|
RC_INTERNAL_SERVER_ERROR, |
1027
|
|
|
|
|
|
|
"$me: Error opening tmpfile: $@" |
1028
|
|
|
|
|
|
|
); |
1029
|
0
|
|
|
|
|
0
|
next; |
1030
|
|
|
|
|
|
|
} |
1031
|
|
|
|
|
|
|
# Make it auto-flush |
1032
|
0
|
|
|
|
|
0
|
$resp_fh->autoflush(); |
1033
|
|
|
|
|
|
|
|
1034
|
|
|
|
|
|
|
# Now that we have it, spool the response to it. This is a |
1035
|
|
|
|
|
|
|
# little hairy, since we still have to allow for compression. |
1036
|
|
|
|
|
|
|
# And though the response could theoretically be HUGE, in |
1037
|
|
|
|
|
|
|
# order to compress we have to write it to a second temp-file |
1038
|
|
|
|
|
|
|
# first, so that we can compress it into the primary handle. |
1039
|
0
|
0
|
|
|
|
0
|
if ($do_compress) |
1040
|
|
|
|
|
|
|
{ |
1041
|
|
|
|
|
|
|
my $fh_compress = |
1042
|
0
|
|
|
|
|
0
|
eval { File::Temp->new(UNLINK => 1, DIR => $tmpdir) }; |
|
0
|
|
|
|
|
0
|
|
1043
|
0
|
0
|
|
|
|
0
|
if (! $fh_compress) |
1044
|
|
|
|
|
|
|
{ |
1045
|
0
|
|
|
|
|
0
|
$conn->send_error( |
1046
|
|
|
|
|
|
|
RC_INTERNAL_SERVER_ERROR, |
1047
|
|
|
|
|
|
|
"$me: Error opening compression tmpfile: $@" |
1048
|
|
|
|
|
|
|
); |
1049
|
0
|
|
|
|
|
0
|
next; |
1050
|
|
|
|
|
|
|
} |
1051
|
|
|
|
|
|
|
# Make it auto-flush |
1052
|
0
|
|
|
|
|
0
|
$fh_compress->autoflush(); |
1053
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
# Write the request to the second FH |
1055
|
0
|
|
|
|
|
0
|
$respxml->serialize($fh_compress); |
1056
|
0
|
|
|
|
|
0
|
seek $fh_compress, 0, 0; |
1057
|
|
|
|
|
|
|
|
1058
|
|
|
|
|
|
|
# Spin up the compression engine |
1059
|
0
|
0
|
|
|
|
0
|
if (! ($com_engine = Compress::Zlib::deflateInit())) |
1060
|
|
|
|
|
|
|
{ |
1061
|
0
|
|
|
|
|
0
|
$conn->send_error(RC_INTERNAL_SERVER_ERROR, |
1062
|
|
|
|
|
|
|
"$me: Unable to initialize the " . |
1063
|
|
|
|
|
|
|
'Compress::Zlib engine'); |
1064
|
0
|
|
|
|
|
0
|
next; |
1065
|
|
|
|
|
|
|
} |
1066
|
|
|
|
|
|
|
|
1067
|
|
|
|
|
|
|
# Spool from the second FH through the compression engine, |
1068
|
|
|
|
|
|
|
# into the intended FH. |
1069
|
0
|
|
|
|
|
0
|
$buf = q{}; |
1070
|
0
|
|
|
|
|
0
|
my $out; |
1071
|
0
|
|
|
|
|
0
|
while (read $fh_compress, $buf, 4096) |
1072
|
|
|
|
|
|
|
{ |
1073
|
0
|
0
|
|
|
|
0
|
if (! defined($out = $com_engine->deflate(\$buf))) |
1074
|
|
|
|
|
|
|
{ |
1075
|
0
|
|
|
|
|
0
|
$conn->send_error(RC_INTERNAL_SERVER_ERROR, |
1076
|
|
|
|
|
|
|
"$me: Compression failure in " . 'deflate()'); |
1077
|
0
|
|
|
|
|
0
|
next; |
1078
|
|
|
|
|
|
|
} |
1079
|
0
|
|
|
|
|
0
|
print {$resp_fh} $out; |
|
0
|
|
|
|
|
0
|
|
1080
|
|
|
|
|
|
|
} |
1081
|
|
|
|
|
|
|
# Make sure we have all that's left |
1082
|
0
|
0
|
|
|
|
0
|
if (! defined($out = $com_engine->flush)) |
1083
|
|
|
|
|
|
|
{ |
1084
|
0
|
|
|
|
|
0
|
$conn->send_error(RC_INTERNAL_SERVER_ERROR, |
1085
|
|
|
|
|
|
|
"$me: Compression flush failure in deflate()"); |
1086
|
0
|
|
|
|
|
0
|
next; |
1087
|
|
|
|
|
|
|
} |
1088
|
0
|
|
|
|
|
0
|
print {$resp_fh} $out; |
|
0
|
|
|
|
|
0
|
|
1089
|
|
|
|
|
|
|
|
1090
|
|
|
|
|
|
|
# Close the secondary FH. Rewinding the primary is done |
1091
|
|
|
|
|
|
|
# later. |
1092
|
0
|
0
|
|
|
|
0
|
if (! close $fh_compress) |
1093
|
|
|
|
|
|
|
{ |
1094
|
0
|
|
|
|
|
0
|
carp "Error closing temp file: $!"; |
1095
|
|
|
|
|
|
|
} |
1096
|
|
|
|
|
|
|
} |
1097
|
|
|
|
|
|
|
else |
1098
|
|
|
|
|
|
|
{ |
1099
|
0
|
|
|
|
|
0
|
$respxml->serialize($resp_fh); |
1100
|
|
|
|
|
|
|
} |
1101
|
0
|
|
|
|
|
0
|
seek $resp_fh, 0, 0; |
1102
|
|
|
|
|
|
|
|
1103
|
0
|
|
|
|
|
0
|
$resp->content_length(-s $resp_fh); |
1104
|
|
|
|
|
|
|
$resp->content( |
1105
|
|
|
|
|
|
|
sub { |
1106
|
0
|
|
|
0
|
|
0
|
my $buffer = q{}; |
1107
|
0
|
0
|
|
|
|
0
|
if (! defined(read $resp_fh, $buffer, 4096)) |
1108
|
|
|
|
|
|
|
{ |
1109
|
0
|
|
|
|
|
0
|
return; |
1110
|
|
|
|
|
|
|
} |
1111
|
0
|
|
|
|
|
0
|
$buffer; |
1112
|
|
|
|
|
|
|
} |
1113
|
0
|
|
|
|
|
0
|
); |
1114
|
|
|
|
|
|
|
} |
1115
|
|
|
|
|
|
|
else |
1116
|
|
|
|
|
|
|
{ |
1117
|
|
|
|
|
|
|
# Treat the content strictly in-memory |
1118
|
0
|
|
|
|
|
0
|
utf8::encode($buf = $respxml->as_string); |
1119
|
0
|
0
|
|
|
|
0
|
if ($do_compress) |
1120
|
|
|
|
|
|
|
{ |
1121
|
0
|
|
|
|
|
0
|
$buf = Compress::Zlib::compress($buf); |
1122
|
|
|
|
|
|
|
} |
1123
|
0
|
|
|
|
|
0
|
$resp->content($buf); |
1124
|
|
|
|
|
|
|
# With $buf force-downgraded to octets, length() should work |
1125
|
0
|
|
|
|
|
0
|
$resp->content_length(length $buf); |
1126
|
|
|
|
|
|
|
} |
1127
|
|
|
|
|
|
|
|
1128
|
0
|
|
|
|
|
0
|
my $eval = eval { |
1129
|
0
|
|
|
0
|
|
0
|
local $SIG{PIPE} = sub { die "Caught SIGPIPE\n"; }; |
|
0
|
|
|
|
|
0
|
|
1130
|
0
|
|
|
|
|
0
|
$conn->send_response($resp); |
1131
|
0
|
|
|
|
|
0
|
1; |
1132
|
|
|
|
|
|
|
}; |
1133
|
0
|
0
|
0
|
|
|
0
|
if (! $eval && $@ && $@ =~ /Caught SIGPIPE/) |
|
|
|
0
|
|
|
|
|
1134
|
|
|
|
|
|
|
{ |
1135
|
|
|
|
|
|
|
# Client disconnected, maybe even before we started sending |
1136
|
|
|
|
|
|
|
# our response. Either way, $conn is useless now. |
1137
|
0
|
|
|
|
|
0
|
undef $conn; |
1138
|
|
|
|
|
|
|
} |
1139
|
0
|
|
|
|
|
0
|
undef $resp; |
1140
|
|
|
|
|
|
|
} |
1141
|
|
|
|
|
|
|
else |
1142
|
|
|
|
|
|
|
{ |
1143
|
0
|
|
|
|
|
0
|
$conn->send_error(RC_FORBIDDEN); |
1144
|
|
|
|
|
|
|
} |
1145
|
|
|
|
|
|
|
} |
1146
|
|
|
|
|
|
|
|
1147
|
0
|
|
|
|
|
0
|
return; |
1148
|
|
|
|
|
|
|
} |
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
############################################################################### |
1151
|
|
|
|
|
|
|
# |
1152
|
|
|
|
|
|
|
# Sub Name: dispatch |
1153
|
|
|
|
|
|
|
# |
1154
|
|
|
|
|
|
|
# Description: Route the request by parsing it, determining what the |
1155
|
|
|
|
|
|
|
# Perl routine should be, etc. |
1156
|
|
|
|
|
|
|
# |
1157
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1158
|
|
|
|
|
|
|
# $self in ref Object of this class |
1159
|
|
|
|
|
|
|
# $xml in ref Reference to the XML text, or |
1160
|
|
|
|
|
|
|
# a RPC::XML::request object. |
1161
|
|
|
|
|
|
|
# If it is a listref, assume |
1162
|
|
|
|
|
|
|
# [ name, @args ]. |
1163
|
|
|
|
|
|
|
# $reftable in hashref If present, a reference to the |
1164
|
|
|
|
|
|
|
# current-running table of |
1165
|
|
|
|
|
|
|
# back-references |
1166
|
|
|
|
|
|
|
# |
1167
|
|
|
|
|
|
|
# Returns: RPC::XML::response object |
1168
|
|
|
|
|
|
|
# |
1169
|
|
|
|
|
|
|
############################################################################### |
1170
|
|
|
|
|
|
|
sub dispatch |
1171
|
|
|
|
|
|
|
{ |
1172
|
0
|
|
|
0
|
1
|
0
|
my ($self, $xml) = @_; |
1173
|
|
|
|
|
|
|
|
1174
|
0
|
|
|
|
|
0
|
my ($reqobj, @args, $response, $name, $meth); |
1175
|
|
|
|
|
|
|
|
1176
|
0
|
0
|
0
|
|
|
0
|
if (ref $xml eq 'SCALAR') |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1177
|
|
|
|
|
|
|
{ |
1178
|
0
|
|
|
|
|
0
|
$reqobj = $self->parser->parse(${$xml}); |
|
0
|
|
|
|
|
0
|
|
1179
|
0
|
0
|
|
|
|
0
|
if (! ref $reqobj) |
1180
|
|
|
|
|
|
|
{ |
1181
|
0
|
|
|
|
|
0
|
return RPC::XML::response-> |
1182
|
|
|
|
|
|
|
new($self->server_fault(badxml => $reqobj)); |
1183
|
|
|
|
|
|
|
} |
1184
|
|
|
|
|
|
|
} |
1185
|
|
|
|
|
|
|
elsif (ref $xml eq 'ARRAY') |
1186
|
|
|
|
|
|
|
{ |
1187
|
|
|
|
|
|
|
# This is sort of a cheat, to make the system.multicall API call a |
1188
|
|
|
|
|
|
|
# lot easier. The syntax isn't documented in the manual page, for good |
1189
|
|
|
|
|
|
|
# reason. |
1190
|
0
|
|
|
|
|
0
|
$reqobj = RPC::XML::request->new(@{$xml}); |
|
0
|
|
|
|
|
0
|
|
1191
|
|
|
|
|
|
|
} |
1192
|
|
|
|
|
|
|
elsif (blessed $xml && $xml->isa('RPC::XML::request')) |
1193
|
|
|
|
|
|
|
{ |
1194
|
0
|
|
|
|
|
0
|
$reqobj = $xml; |
1195
|
|
|
|
|
|
|
} |
1196
|
|
|
|
|
|
|
else |
1197
|
|
|
|
|
|
|
{ |
1198
|
0
|
|
|
|
|
0
|
$reqobj = $self->parser->parse($xml); |
1199
|
0
|
0
|
|
|
|
0
|
if (! ref $reqobj) |
1200
|
|
|
|
|
|
|
{ |
1201
|
0
|
|
|
|
|
0
|
return RPC::XML::response-> |
1202
|
|
|
|
|
|
|
new($self->server_fault(badxml => $reqobj)); |
1203
|
|
|
|
|
|
|
} |
1204
|
|
|
|
|
|
|
} |
1205
|
|
|
|
|
|
|
|
1206
|
0
|
|
|
|
|
0
|
@args = @{$reqobj->args}; |
|
0
|
|
|
|
|
0
|
|
1207
|
0
|
|
|
|
|
0
|
$name = $reqobj->name; |
1208
|
|
|
|
|
|
|
|
1209
|
|
|
|
|
|
|
# Get the method, call it, and bump the internal requests counter. Create |
1210
|
|
|
|
|
|
|
# a fault object if there is problem with the method object itself. |
1211
|
0
|
|
|
|
|
0
|
$meth = $self->get_method($name); |
1212
|
0
|
0
|
|
|
|
0
|
if (ref $meth) |
1213
|
|
|
|
|
|
|
{ |
1214
|
0
|
|
|
|
|
0
|
$response = $meth->call($self, @args); |
1215
|
0
|
0
|
0
|
|
|
0
|
if (! (($name eq 'system.status') && |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1216
|
|
|
|
|
|
|
@args && |
1217
|
|
|
|
|
|
|
($args[0]->type eq 'boolean') && |
1218
|
|
|
|
|
|
|
($args[0]->value))) |
1219
|
|
|
|
|
|
|
{ |
1220
|
0
|
|
|
|
|
0
|
$self->{__requests}++; |
1221
|
|
|
|
|
|
|
} |
1222
|
|
|
|
|
|
|
} |
1223
|
|
|
|
|
|
|
else |
1224
|
|
|
|
|
|
|
{ |
1225
|
0
|
|
|
|
|
0
|
$response = $self->server_fault( |
1226
|
|
|
|
|
|
|
badmethod => "No method '$meth' on server" |
1227
|
|
|
|
|
|
|
); |
1228
|
|
|
|
|
|
|
} |
1229
|
|
|
|
|
|
|
|
1230
|
|
|
|
|
|
|
# All the eval'ing and error-trapping happened within the method class |
1231
|
0
|
|
|
|
|
0
|
return RPC::XML::response->new($response); |
1232
|
|
|
|
|
|
|
} |
1233
|
|
|
|
|
|
|
|
1234
|
|
|
|
|
|
|
############################################################################### |
1235
|
|
|
|
|
|
|
# |
1236
|
|
|
|
|
|
|
# Sub Name: call |
1237
|
|
|
|
|
|
|
# |
1238
|
|
|
|
|
|
|
# Description: This is an internal, end-run-around-dispatch() method to |
1239
|
|
|
|
|
|
|
# allow the RPC methods that this server has and knows about |
1240
|
|
|
|
|
|
|
# to call each other through their reference to the server |
1241
|
|
|
|
|
|
|
# object. |
1242
|
|
|
|
|
|
|
# |
1243
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1244
|
|
|
|
|
|
|
# $self in ref Object of this class |
1245
|
|
|
|
|
|
|
# $name in scalar Name of the method to call |
1246
|
|
|
|
|
|
|
# @args in list Arguments (if any) to pass |
1247
|
|
|
|
|
|
|
# |
1248
|
|
|
|
|
|
|
# Returns: Success: return value of the call |
1249
|
|
|
|
|
|
|
# Failure: error string |
1250
|
|
|
|
|
|
|
# |
1251
|
|
|
|
|
|
|
############################################################################### |
1252
|
|
|
|
|
|
|
sub call |
1253
|
|
|
|
|
|
|
{ |
1254
|
0
|
|
|
0
|
0
|
0
|
my ($self, $name, @args) = @_; |
1255
|
|
|
|
|
|
|
|
1256
|
0
|
|
|
|
|
0
|
my $meth; |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
# Two VERY important notes here: The values in @args are not pre-treated |
1259
|
|
|
|
|
|
|
# in any way, so not only should the receiver understand what they're |
1260
|
|
|
|
|
|
|
# getting, there's no signature checking taking place, either. |
1261
|
|
|
|
|
|
|
# |
1262
|
|
|
|
|
|
|
# Second, if the normal return value is not distinguishable from a string, |
1263
|
|
|
|
|
|
|
# then the caller may not recognize if an error occurs. |
1264
|
|
|
|
|
|
|
|
1265
|
0
|
|
|
|
|
0
|
$meth = $self->get_method($name); |
1266
|
0
|
0
|
|
|
|
0
|
if (! ref $meth) |
1267
|
|
|
|
|
|
|
{ |
1268
|
0
|
|
|
|
|
0
|
return $meth; |
1269
|
|
|
|
|
|
|
} |
1270
|
|
|
|
|
|
|
|
1271
|
0
|
|
|
|
|
0
|
return $meth->call($self, @args); |
1272
|
|
|
|
|
|
|
} |
1273
|
|
|
|
|
|
|
|
1274
|
|
|
|
|
|
|
############################################################################### |
1275
|
|
|
|
|
|
|
# |
1276
|
|
|
|
|
|
|
# Sub Name: add_default_methods |
1277
|
|
|
|
|
|
|
# |
1278
|
|
|
|
|
|
|
# Description: This adds all the methods that were shipped with this |
1279
|
|
|
|
|
|
|
# package, by threading through to add_methods_in_dir() |
1280
|
|
|
|
|
|
|
# with the global constant $INSTALL_DIR. |
1281
|
|
|
|
|
|
|
# |
1282
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1283
|
|
|
|
|
|
|
# $self in ref Object reference/static class |
1284
|
|
|
|
|
|
|
# @details in ref Details of names to add or skip |
1285
|
|
|
|
|
|
|
# |
1286
|
|
|
|
|
|
|
# Returns: $self |
1287
|
|
|
|
|
|
|
# |
1288
|
|
|
|
|
|
|
############################################################################### |
1289
|
|
|
|
|
|
|
sub add_default_methods |
1290
|
|
|
|
|
|
|
{ |
1291
|
1
|
|
|
1
|
1
|
2
|
my ($self, @details) = @_; |
1292
|
|
|
|
|
|
|
|
1293
|
1
|
|
|
|
|
6
|
return $self->add_methods_in_dir($self->INSTALL_DIR, @details); |
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
|
1296
|
|
|
|
|
|
|
############################################################################### |
1297
|
|
|
|
|
|
|
# |
1298
|
|
|
|
|
|
|
# Sub Name: add_methods_in_dir |
1299
|
|
|
|
|
|
|
# |
1300
|
|
|
|
|
|
|
# Description: This adds all methods specified in the directory passed, |
1301
|
|
|
|
|
|
|
# in accordance with the details specified. |
1302
|
|
|
|
|
|
|
# |
1303
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1304
|
|
|
|
|
|
|
# $self in ref Class instance |
1305
|
|
|
|
|
|
|
# $dir in scalar Directory to scan |
1306
|
|
|
|
|
|
|
# @details in list Possible hanky-panky with the |
1307
|
|
|
|
|
|
|
# list of methods to install |
1308
|
|
|
|
|
|
|
# |
1309
|
|
|
|
|
|
|
# Returns: $self |
1310
|
|
|
|
|
|
|
# |
1311
|
|
|
|
|
|
|
############################################################################### |
1312
|
|
|
|
|
|
|
sub add_methods_in_dir |
1313
|
|
|
|
|
|
|
{ |
1314
|
1
|
|
|
1
|
1
|
2
|
my ($self, $dir, @details) = @_; |
1315
|
|
|
|
|
|
|
|
1316
|
1
|
|
|
|
|
2
|
my $negate = 0; |
1317
|
1
|
|
|
|
|
2
|
my $detail = 0; |
1318
|
1
|
|
|
|
|
1
|
my (%details, $ret); |
1319
|
|
|
|
|
|
|
|
1320
|
1
|
50
|
|
|
|
6
|
if (@details) |
1321
|
|
|
|
|
|
|
{ |
1322
|
0
|
|
|
|
|
0
|
$detail = 1; |
1323
|
0
|
0
|
|
|
|
0
|
if ($details[0] =~ /^-?except/i) |
1324
|
|
|
|
|
|
|
{ |
1325
|
0
|
|
|
|
|
0
|
$negate = 1; |
1326
|
0
|
|
|
|
|
0
|
shift @details; |
1327
|
|
|
|
|
|
|
} |
1328
|
0
|
|
|
|
|
0
|
for (@details) |
1329
|
|
|
|
|
|
|
{ |
1330
|
0
|
0
|
|
|
|
0
|
if (! /[.]xpl$/) |
1331
|
|
|
|
|
|
|
{ |
1332
|
0
|
|
|
|
|
0
|
$_ .= '.xpl'; |
1333
|
|
|
|
|
|
|
} |
1334
|
|
|
|
|
|
|
} |
1335
|
0
|
|
|
|
|
0
|
@details{@details} = (1) x @details; |
1336
|
|
|
|
|
|
|
} |
1337
|
|
|
|
|
|
|
|
1338
|
1
|
|
|
|
|
1
|
my $dh; |
1339
|
1
|
50
|
|
|
|
37
|
if (! opendir $dh, $dir) |
1340
|
|
|
|
|
|
|
{ |
1341
|
0
|
|
|
|
|
0
|
return "Error opening $dir for reading: $!"; |
1342
|
|
|
|
|
|
|
} |
1343
|
1
|
|
|
|
|
52
|
my @files = grep { $_ =~ /[.]xpl$/ } readdir $dh; |
|
15
|
|
|
|
|
22
|
|
1344
|
1
|
|
|
|
|
10
|
closedir $dh; |
1345
|
|
|
|
|
|
|
|
1346
|
1
|
|
|
|
|
2
|
for my $file (@files) |
1347
|
|
|
|
|
|
|
{ |
1348
|
|
|
|
|
|
|
# Use $detail as a short-circuit to avoid the other tests when we can |
1349
|
1
|
0
|
33
|
|
|
3
|
if ($detail && |
|
|
0
|
|
|
|
|
|
1350
|
|
|
|
|
|
|
($negate ? $details{$file} : ! $details{$file})) |
1351
|
|
|
|
|
|
|
{ |
1352
|
0
|
|
|
|
|
0
|
next; |
1353
|
|
|
|
|
|
|
} |
1354
|
|
|
|
|
|
|
# n.b.: Giving the full path keeps add_method from having to search |
1355
|
1
|
|
|
|
|
20
|
$ret = $self->add_method(File::Spec->catfile($dir, $file)); |
1356
|
0
|
0
|
|
|
|
0
|
if (! ref $ret) |
1357
|
|
|
|
|
|
|
{ |
1358
|
0
|
|
|
|
|
0
|
return $ret; |
1359
|
|
|
|
|
|
|
} |
1360
|
|
|
|
|
|
|
} |
1361
|
|
|
|
|
|
|
|
1362
|
0
|
|
|
|
|
0
|
return $self; |
1363
|
|
|
|
|
|
|
} |
1364
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
# For name-symmetry: |
1366
|
|
|
|
|
|
|
*add_procedures_in_dir = *add_functions_in_dir = \&add_methods_in_dir; |
1367
|
|
|
|
|
|
|
|
1368
|
|
|
|
|
|
|
############################################################################### |
1369
|
|
|
|
|
|
|
# |
1370
|
|
|
|
|
|
|
# Sub Name: delete_method |
1371
|
|
|
|
|
|
|
# |
1372
|
|
|
|
|
|
|
# Description: Remove any current binding for the named method on the |
1373
|
|
|
|
|
|
|
# calling server object. Note that if this method is shared |
1374
|
|
|
|
|
|
|
# across other server objects, it won't be destroyed until |
1375
|
|
|
|
|
|
|
# the last server deletes it. |
1376
|
|
|
|
|
|
|
# |
1377
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1378
|
|
|
|
|
|
|
# $self in ref Object of this class |
1379
|
|
|
|
|
|
|
# $name in scalar Name of method to lost |
1380
|
|
|
|
|
|
|
# |
1381
|
|
|
|
|
|
|
# Returns: Success: $self |
1382
|
|
|
|
|
|
|
# Failure: error message |
1383
|
|
|
|
|
|
|
# |
1384
|
|
|
|
|
|
|
############################################################################### |
1385
|
|
|
|
|
|
|
sub delete_method |
1386
|
|
|
|
|
|
|
{ |
1387
|
0
|
|
|
0
|
1
|
0
|
my ($self, $name) = @_; |
1388
|
|
|
|
|
|
|
|
1389
|
0
|
0
|
|
|
|
0
|
if ($name) |
1390
|
|
|
|
|
|
|
{ |
1391
|
0
|
0
|
|
|
|
0
|
if ($self->{__method_table}->{$name}) |
1392
|
|
|
|
|
|
|
{ |
1393
|
0
|
|
|
|
|
0
|
delete $self->{__method_table}->{$name}; |
1394
|
|
|
|
|
|
|
} |
1395
|
|
|
|
|
|
|
} |
1396
|
|
|
|
|
|
|
else |
1397
|
|
|
|
|
|
|
{ |
1398
|
0
|
|
|
|
|
0
|
return ref $self . "::delete_method: No such method $name"; |
1399
|
|
|
|
|
|
|
} |
1400
|
|
|
|
|
|
|
|
1401
|
0
|
|
|
|
|
0
|
return $self; |
1402
|
|
|
|
|
|
|
} |
1403
|
|
|
|
|
|
|
|
1404
|
|
|
|
|
|
|
# For name-symmetry: |
1405
|
|
|
|
|
|
|
*delete_procedure = *delete_function = \&delete_method; |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
############################################################################### |
1408
|
|
|
|
|
|
|
# |
1409
|
|
|
|
|
|
|
# Sub Name: list_methods |
1410
|
|
|
|
|
|
|
# |
1411
|
|
|
|
|
|
|
# Description: Return a list of the methods this object has published. |
1412
|
|
|
|
|
|
|
# Returns the names, not the objects. |
1413
|
|
|
|
|
|
|
# |
1414
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1415
|
|
|
|
|
|
|
# $self in ref Object of this class |
1416
|
|
|
|
|
|
|
# |
1417
|
|
|
|
|
|
|
# Returns: List of names, possibly empty |
1418
|
|
|
|
|
|
|
# |
1419
|
|
|
|
|
|
|
############################################################################### |
1420
|
|
|
|
|
|
|
sub list_methods |
1421
|
|
|
|
|
|
|
{ |
1422
|
0
|
|
|
0
|
1
|
0
|
return keys %{shift->{__method_table}}; |
|
0
|
|
|
|
|
0
|
|
1423
|
|
|
|
|
|
|
} |
1424
|
|
|
|
|
|
|
|
1425
|
|
|
|
|
|
|
# For name-symmetry: |
1426
|
|
|
|
|
|
|
*list_procedures = *list_functions = \&list_methods; |
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
############################################################################### |
1429
|
|
|
|
|
|
|
# |
1430
|
|
|
|
|
|
|
# Sub Name: share_methods |
1431
|
|
|
|
|
|
|
# |
1432
|
|
|
|
|
|
|
# Description: Share the named methods as found on $src_srv into the |
1433
|
|
|
|
|
|
|
# method table of the calling object. |
1434
|
|
|
|
|
|
|
# |
1435
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1436
|
|
|
|
|
|
|
# $self in ref Object of this class |
1437
|
|
|
|
|
|
|
# $src_srv in ref Another object of this class |
1438
|
|
|
|
|
|
|
# @names in list One or more method names |
1439
|
|
|
|
|
|
|
# |
1440
|
|
|
|
|
|
|
# Returns: Success: $self |
1441
|
|
|
|
|
|
|
# Failure: error message |
1442
|
|
|
|
|
|
|
# |
1443
|
|
|
|
|
|
|
############################################################################### |
1444
|
|
|
|
|
|
|
sub share_methods |
1445
|
|
|
|
|
|
|
{ |
1446
|
0
|
|
|
0
|
1
|
0
|
my ($self, $src_srv, @names) = @_; |
1447
|
|
|
|
|
|
|
|
1448
|
0
|
|
|
|
|
0
|
my ($me, $pkg, %methods, @methods, $meth, @list, @missing); |
1449
|
|
|
|
|
|
|
|
1450
|
0
|
|
|
|
|
0
|
$me = ref($self) . '::share_methods'; |
1451
|
0
|
|
|
|
|
0
|
$pkg = __PACKAGE__; # So it can go inside quoted strings |
1452
|
|
|
|
|
|
|
|
1453
|
0
|
0
|
0
|
|
|
0
|
if (! (blessed $src_srv && $src_srv->isa($pkg))) |
1454
|
|
|
|
|
|
|
{ |
1455
|
0
|
|
|
|
|
0
|
return "$me: First arg not derived from $pkg, cannot share"; |
1456
|
|
|
|
|
|
|
} |
1457
|
0
|
0
|
|
|
|
0
|
if (! @names) |
1458
|
|
|
|
|
|
|
{ |
1459
|
0
|
|
|
|
|
0
|
return "$me: Must specify at least one method name for sharing"; |
1460
|
|
|
|
|
|
|
} |
1461
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
# Scan @names for any regex objects, and if found insert the matches into |
1463
|
|
|
|
|
|
|
# the list. |
1464
|
|
|
|
|
|
|
# |
1465
|
|
|
|
|
|
|
# Only do this once: |
1466
|
0
|
|
|
|
|
0
|
@methods = keys %{$src_srv->{__method_table}}; |
|
0
|
|
|
|
|
0
|
|
1467
|
0
|
|
|
|
|
0
|
for my $name (@names) |
1468
|
|
|
|
|
|
|
{ |
1469
|
0
|
0
|
|
|
|
0
|
if (ref $name eq 'Regexp') |
1470
|
|
|
|
|
|
|
{ |
1471
|
0
|
|
|
|
|
0
|
for (grep { $_ =~ $name } @methods) |
|
0
|
|
|
|
|
0
|
|
1472
|
|
|
|
|
|
|
{ |
1473
|
0
|
|
|
|
|
0
|
$methods{$_}++; |
1474
|
|
|
|
|
|
|
} |
1475
|
|
|
|
|
|
|
} |
1476
|
|
|
|
|
|
|
else |
1477
|
|
|
|
|
|
|
{ |
1478
|
0
|
|
|
|
|
0
|
$methods{$name}++; |
1479
|
|
|
|
|
|
|
} |
1480
|
|
|
|
|
|
|
} |
1481
|
|
|
|
|
|
|
# This has the benefit of trimming any redundancies caused by regex's |
1482
|
0
|
|
|
|
|
0
|
@names = keys %methods; |
1483
|
|
|
|
|
|
|
|
1484
|
|
|
|
|
|
|
# Note that the method refs are saved until we've verified all of them. |
1485
|
|
|
|
|
|
|
# If we have to return a failure message, I don't want to leave a half- |
1486
|
|
|
|
|
|
|
# finished job or have to go back and undo (n-1) additions because of one |
1487
|
|
|
|
|
|
|
# failure. |
1488
|
0
|
|
|
|
|
0
|
for (@names) |
1489
|
|
|
|
|
|
|
{ |
1490
|
0
|
|
|
|
|
0
|
$meth = $src_srv->get_method($_); |
1491
|
0
|
0
|
|
|
|
0
|
if (ref $meth) |
1492
|
|
|
|
|
|
|
{ |
1493
|
0
|
|
|
|
|
0
|
push @list, $meth; |
1494
|
|
|
|
|
|
|
} |
1495
|
|
|
|
|
|
|
else |
1496
|
|
|
|
|
|
|
{ |
1497
|
0
|
|
|
|
|
0
|
push @missing, $_; |
1498
|
|
|
|
|
|
|
} |
1499
|
|
|
|
|
|
|
} |
1500
|
|
|
|
|
|
|
|
1501
|
0
|
0
|
|
|
|
0
|
if (@missing) |
1502
|
|
|
|
|
|
|
{ |
1503
|
0
|
|
|
|
|
0
|
return "$me: One or more methods not found on source object: " . |
1504
|
|
|
|
|
|
|
join q{ } => @missing; |
1505
|
|
|
|
|
|
|
} |
1506
|
|
|
|
|
|
|
else |
1507
|
|
|
|
|
|
|
{ |
1508
|
0
|
|
|
|
|
0
|
for (@list) |
1509
|
|
|
|
|
|
|
{ |
1510
|
0
|
|
|
|
|
0
|
$self->add_method($_); |
1511
|
|
|
|
|
|
|
} |
1512
|
|
|
|
|
|
|
} |
1513
|
|
|
|
|
|
|
|
1514
|
0
|
|
|
|
|
0
|
return $self; |
1515
|
|
|
|
|
|
|
} |
1516
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
# For name-symmetry: |
1518
|
|
|
|
|
|
|
*share_procedures = *share_functions = \&share_methods; |
1519
|
|
|
|
|
|
|
|
1520
|
|
|
|
|
|
|
############################################################################### |
1521
|
|
|
|
|
|
|
# |
1522
|
|
|
|
|
|
|
# Sub Name: copy_methods |
1523
|
|
|
|
|
|
|
# |
1524
|
|
|
|
|
|
|
# Description: Copy the named methods as found on $src_srv into the |
1525
|
|
|
|
|
|
|
# method table of the calling object. This differs from |
1526
|
|
|
|
|
|
|
# share() above in that only the coderef is shared, the |
1527
|
|
|
|
|
|
|
# rest of the method is a completely new object. |
1528
|
|
|
|
|
|
|
# |
1529
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1530
|
|
|
|
|
|
|
# $self in ref Object of this class |
1531
|
|
|
|
|
|
|
# $src_srv in ref Another object of this class |
1532
|
|
|
|
|
|
|
# @names in list One or more method names |
1533
|
|
|
|
|
|
|
# |
1534
|
|
|
|
|
|
|
# Returns: Success: $self |
1535
|
|
|
|
|
|
|
# Failure: error message |
1536
|
|
|
|
|
|
|
# |
1537
|
|
|
|
|
|
|
############################################################################### |
1538
|
|
|
|
|
|
|
sub copy_methods |
1539
|
|
|
|
|
|
|
{ |
1540
|
0
|
|
|
0
|
1
|
0
|
my ($self, $src_srv, @names) = @_; |
1541
|
|
|
|
|
|
|
|
1542
|
0
|
|
|
|
|
0
|
my ($me, $pkg, %methods, @methods, $meth, @list, @missing); |
1543
|
|
|
|
|
|
|
|
1544
|
0
|
|
|
|
|
0
|
$me = ref($self) . '::copy_methods'; |
1545
|
0
|
|
|
|
|
0
|
$pkg = __PACKAGE__; # So it can go inside quoted strings |
1546
|
|
|
|
|
|
|
|
1547
|
0
|
0
|
0
|
|
|
0
|
if (! (blessed $src_srv && $src_srv->isa($pkg))) |
1548
|
|
|
|
|
|
|
{ |
1549
|
0
|
|
|
|
|
0
|
return "$me: First arg not derived from $pkg, cannot copy"; |
1550
|
|
|
|
|
|
|
} |
1551
|
0
|
0
|
|
|
|
0
|
if (! @names) |
1552
|
|
|
|
|
|
|
{ |
1553
|
0
|
|
|
|
|
0
|
return "$me: Must specify at least one method name/regex for copying"; |
1554
|
|
|
|
|
|
|
} |
1555
|
|
|
|
|
|
|
|
1556
|
|
|
|
|
|
|
# Scan @names for any regez objects, and if found insert the matches into |
1557
|
|
|
|
|
|
|
# the list. |
1558
|
|
|
|
|
|
|
# |
1559
|
|
|
|
|
|
|
# Only do this once: |
1560
|
0
|
|
|
|
|
0
|
@methods = keys %{$src_srv->{__method_table}}; |
|
0
|
|
|
|
|
0
|
|
1561
|
0
|
|
|
|
|
0
|
for my $name (@names) |
1562
|
|
|
|
|
|
|
{ |
1563
|
0
|
0
|
|
|
|
0
|
if (ref $name eq 'Regexp') |
1564
|
|
|
|
|
|
|
{ |
1565
|
0
|
|
|
|
|
0
|
for (grep { $_ =~ $name } @methods) |
|
0
|
|
|
|
|
0
|
|
1566
|
|
|
|
|
|
|
{ |
1567
|
0
|
|
|
|
|
0
|
$methods{$_}++; |
1568
|
|
|
|
|
|
|
} |
1569
|
|
|
|
|
|
|
} |
1570
|
|
|
|
|
|
|
else |
1571
|
|
|
|
|
|
|
{ |
1572
|
0
|
|
|
|
|
0
|
$methods{$name}++; |
1573
|
|
|
|
|
|
|
} |
1574
|
|
|
|
|
|
|
} |
1575
|
|
|
|
|
|
|
# This has the benefit of trimming any redundancies caused by regex's |
1576
|
0
|
|
|
|
|
0
|
@names = keys %methods; |
1577
|
|
|
|
|
|
|
|
1578
|
|
|
|
|
|
|
# Note that the method clones are saved until we've verified all of them. |
1579
|
|
|
|
|
|
|
# If we have to return a failure message, I don't want to leave a half- |
1580
|
|
|
|
|
|
|
# finished job or have to go back and undo (n-1) additions because of one |
1581
|
|
|
|
|
|
|
# failure. |
1582
|
0
|
|
|
|
|
0
|
for (@names) |
1583
|
|
|
|
|
|
|
{ |
1584
|
0
|
|
|
|
|
0
|
$meth = $src_srv->get_method($_); |
1585
|
0
|
0
|
|
|
|
0
|
if (ref $meth) |
1586
|
|
|
|
|
|
|
{ |
1587
|
0
|
|
|
|
|
0
|
push @list, $meth->clone; |
1588
|
|
|
|
|
|
|
} |
1589
|
|
|
|
|
|
|
else |
1590
|
|
|
|
|
|
|
{ |
1591
|
0
|
|
|
|
|
0
|
push @missing, $_; |
1592
|
|
|
|
|
|
|
} |
1593
|
|
|
|
|
|
|
} |
1594
|
|
|
|
|
|
|
|
1595
|
0
|
0
|
|
|
|
0
|
if (@missing) |
1596
|
|
|
|
|
|
|
{ |
1597
|
0
|
|
|
|
|
0
|
return "$me: One or more methods not found on source object: @missing"; |
1598
|
|
|
|
|
|
|
} |
1599
|
|
|
|
|
|
|
else |
1600
|
|
|
|
|
|
|
{ |
1601
|
0
|
|
|
|
|
0
|
for (@list) |
1602
|
|
|
|
|
|
|
{ |
1603
|
0
|
|
|
|
|
0
|
$self->add_method($_); |
1604
|
|
|
|
|
|
|
} |
1605
|
|
|
|
|
|
|
} |
1606
|
|
|
|
|
|
|
|
1607
|
0
|
|
|
|
|
0
|
return $self; |
1608
|
|
|
|
|
|
|
} |
1609
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
# For name-symmetry: |
1611
|
|
|
|
|
|
|
*copy_procedures = *copy_functions = \©_methods; |
1612
|
|
|
|
|
|
|
|
1613
|
|
|
|
|
|
|
############################################################################### |
1614
|
|
|
|
|
|
|
# |
1615
|
|
|
|
|
|
|
# Sub Name: timeout |
1616
|
|
|
|
|
|
|
# |
1617
|
|
|
|
|
|
|
# Description: This sets the timeout for processing connections after |
1618
|
|
|
|
|
|
|
# a new connection has been accepted. It returns the old |
1619
|
|
|
|
|
|
|
# timeout value. If you pass in no value, it returns |
1620
|
|
|
|
|
|
|
# the current timeout. |
1621
|
|
|
|
|
|
|
# |
1622
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1623
|
|
|
|
|
|
|
# $self in ref Object reference/static class |
1624
|
|
|
|
|
|
|
# $timeout in ref New timeout value |
1625
|
|
|
|
|
|
|
# |
1626
|
|
|
|
|
|
|
# Returns: $self->{__timeout} |
1627
|
|
|
|
|
|
|
# |
1628
|
|
|
|
|
|
|
############################################################################### |
1629
|
|
|
|
|
|
|
sub timeout |
1630
|
|
|
|
|
|
|
{ |
1631
|
1
|
|
|
1
|
1
|
1
|
my ($self, $timeout) = @_; |
1632
|
|
|
|
|
|
|
|
1633
|
1
|
|
|
|
|
3
|
my $old_timeout = $self->{__timeout}; |
1634
|
1
|
50
|
|
|
|
6
|
if ($timeout) |
1635
|
|
|
|
|
|
|
{ |
1636
|
0
|
|
|
|
|
0
|
$self->{__timeout} = $timeout; |
1637
|
|
|
|
|
|
|
} |
1638
|
|
|
|
|
|
|
|
1639
|
1
|
|
|
|
|
12
|
return $old_timeout; |
1640
|
|
|
|
|
|
|
} |
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
############################################################################### |
1643
|
|
|
|
|
|
|
# |
1644
|
|
|
|
|
|
|
# Sub Name: server_fault |
1645
|
|
|
|
|
|
|
# |
1646
|
|
|
|
|
|
|
# Description: Create a RPC::XML::fault object for the class of error |
1647
|
|
|
|
|
|
|
# and specific message that are passed in. |
1648
|
|
|
|
|
|
|
# |
1649
|
|
|
|
|
|
|
# Arguments: NAME IN/OUT TYPE DESCRIPTION |
1650
|
|
|
|
|
|
|
# $self in ref Object of this class |
1651
|
|
|
|
|
|
|
# $err in scalar Type of error/fault to generate |
1652
|
|
|
|
|
|
|
# $message in scalar Error text for the fault |
1653
|
|
|
|
|
|
|
# |
1654
|
|
|
|
|
|
|
# Returns: RPC::XML::fault instance |
1655
|
|
|
|
|
|
|
# |
1656
|
|
|
|
|
|
|
############################################################################### |
1657
|
|
|
|
|
|
|
sub server_fault |
1658
|
|
|
|
|
|
|
{ |
1659
|
0
|
|
|
0
|
1
|
|
my ($self, $err, $message) = @_; |
1660
|
0
|
|
0
|
|
|
|
$message ||= q{}; # Avoid any "undef" warnings |
1661
|
|
|
|
|
|
|
|
1662
|
0
|
|
|
|
|
|
my ($code, $text); |
1663
|
|
|
|
|
|
|
|
1664
|
0
|
0
|
|
|
|
|
if (my $fault = $self->{__fault_table}->{$err}) |
1665
|
|
|
|
|
|
|
{ |
1666
|
0
|
0
|
|
|
|
|
if (ref $fault) |
1667
|
|
|
|
|
|
|
{ |
1668
|
|
|
|
|
|
|
# This specifies both code and message |
1669
|
0
|
|
|
|
|
|
($code, $text) = @{$fault}; |
|
0
|
|
|
|
|
|
|
1670
|
|
|
|
|
|
|
# Replace (the first) "%s" with $message |
1671
|
0
|
|
|
|
|
|
$text =~ s/%s/$message/; |
1672
|
|
|
|
|
|
|
} |
1673
|
|
|
|
|
|
|
else |
1674
|
|
|
|
|
|
|
{ |
1675
|
|
|
|
|
|
|
# This is just the code, use $message verbatim |
1676
|
0
|
|
|
|
|
|
($code, $text) = ($fault, $message); |
1677
|
|
|
|
|
|
|
} |
1678
|
|
|
|
|
|
|
} |
1679
|
|
|
|
|
|
|
else |
1680
|
|
|
|
|
|
|
{ |
1681
|
0
|
|
|
|
|
|
$code = -1; |
1682
|
0
|
|
|
|
|
|
$text = "Unknown error class '$err' (message is '$message')"; |
1683
|
|
|
|
|
|
|
} |
1684
|
|
|
|
|
|
|
|
1685
|
0
|
|
|
|
|
|
return RPC::XML::fault->new($code, $text); |
1686
|
|
|
|
|
|
|
} |
1687
|
|
|
|
|
|
|
|
1688
|
|
|
|
|
|
|
1; |
1689
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
__END__ |