line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
1
|
|
|
1
|
|
210667
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
48
|
|
2
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
61
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Plack::Middleware::AdaptFilehandleRead; |
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
6
|
use base 'Plack::Middleware'; |
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
898
|
|
7
|
1
|
|
|
1
|
|
9942
|
use Plack::Middleware::AdaptFilehandleRead::Proxy; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
32
|
|
8
|
1
|
|
|
1
|
|
5
|
use Plack::Util::Accessor 'always_adapt', 'chunksize'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
8
|
|
9
|
1
|
|
|
1
|
|
58
|
use Scalar::Util (); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
16
|
|
10
|
1
|
|
|
1
|
|
4
|
use Plack::Util (); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
215
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.003'; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub looks_like_a_readable_fh { |
15
|
1
|
|
|
1
|
0
|
3
|
my $self = shift; |
16
|
1
|
|
50
|
|
|
7
|
my $body = shift || return; # If there's a body |
17
|
1
|
|
33
|
|
|
34
|
return Scalar::Util::blessed($body) && # and its an object |
18
|
|
|
|
|
|
|
$body->can('read') && # which can 'read' |
19
|
|
|
|
|
|
|
($self->always_adapt || # and either ->always_adapt |
20
|
|
|
|
|
|
|
!$body->can('getline')); # or doesn't 'getline' |
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub call { |
24
|
1
|
|
|
1
|
1
|
123337
|
my($self, $env) = @_; |
25
|
1
|
|
|
|
|
17
|
my $res = $self->app->($env); |
26
|
|
|
|
|
|
|
return Plack::Util::response_cb($res, sub { |
27
|
1
|
50
|
|
1
|
|
20
|
if( $self->looks_like_a_readable_fh((my $r = shift)->[2]) ) { |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# We have an filehandle like object that doesn't do ->getline |
30
|
|
|
|
|
|
|
# so Plack can't do anything with it. Wrap it in a proxy object |
31
|
|
|
|
|
|
|
# that adds the ->getline method by adapting read. We assume |
32
|
|
|
|
|
|
|
# this ->read works like $fh->read(BUF, LEN, [OFFSET]). |
33
|
|
|
|
|
|
|
|
34
|
1
|
|
50
|
|
|
16
|
$r->[2] = Plack::Middleware::AdaptFilehandleRead::Proxy->new($r->[2], ($self->chunksize || 65536)); |
35
|
|
|
|
|
|
|
} |
36
|
1
|
|
|
|
|
109
|
}); |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
1; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head1 NAME |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
Plack::Middleware::AdaptFilehandleRead - Give a filehandle a getline method when its missing |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=head1 SYNOPSIS |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
use Plack::Builder; |
48
|
|
|
|
|
|
|
use AppReturnsFileHandleWithRead; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
my $app = AppReturnsFileHandleWithRead->new; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
builder { |
53
|
|
|
|
|
|
|
enable 'AdaptFilehandleRead'; |
54
|
|
|
|
|
|
|
$app; |
55
|
|
|
|
|
|
|
}; |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 DESCRIPTION |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
L allows for the body content to be a glob filehandle or a Filehandle |
60
|
|
|
|
|
|
|
like object. For the later case the object must have a method C |
61
|
|
|
|
|
|
|
which works as described in L. However sometimes you may have |
62
|
|
|
|
|
|
|
a custom filehandle like object that support the common C method. For |
63
|
|
|
|
|
|
|
example many versions of L allowed the body of a response to be a |
64
|
|
|
|
|
|
|
glob or object that does C. People might have written custom streaming |
65
|
|
|
|
|
|
|
applications that had this C method but not C. As a result |
66
|
|
|
|
|
|
|
these custom Filehandle like objects are not compatible with the expectations |
67
|
|
|
|
|
|
|
of L. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
This middleware exists to help you convert such a custom made filehandle like |
70
|
|
|
|
|
|
|
object. If you have created something like this (or for example using some |
71
|
|
|
|
|
|
|
shared code like L that returns a filehandle that does C |
72
|
|
|
|
|
|
|
but not C) you can use this middleware to wrap said object in a proxy |
73
|
|
|
|
|
|
|
that does the C method by reading from the exising C method. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
By default, if this middleware is enabled, it will examine any body values and |
76
|
|
|
|
|
|
|
check if they are 1) an object, 2) that does C and 3) doesn't do C |
77
|
|
|
|
|
|
|
If such a case exists it will create an instance of L |
78
|
|
|
|
|
|
|
which had the C method. It also will delegate any other method calls |
79
|
|
|
|
|
|
|
to the wrapped object via AUTOLOAD so if you have some additional custom methods |
80
|
|
|
|
|
|
|
it will still work as expected. It does not currently proxy any Ling. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
If for some reason your custom filehandle like object does C but its |
83
|
|
|
|
|
|
|
faulty and the C method is correct, you can set C to true |
84
|
|
|
|
|
|
|
and the proxy will be applied even if a C method is detected. |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
builder { |
87
|
|
|
|
|
|
|
enable 'AdaptFilehandleRead', always_adapt=>1; |
88
|
|
|
|
|
|
|
$app; |
89
|
|
|
|
|
|
|
}; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
This middleware will do its best to respect the various allowed values of |
92
|
|
|
|
|
|
|
C<$/> for deciding how to return content from C Currently we support |
93
|
|
|
|
|
|
|
C<$/> values of scalar ref (like \8192 for reading fixed length chunks) or |
94
|
|
|
|
|
|
|
simple scalars (like \n for reading newline delimited records). Currently |
95
|
|
|
|
|
|
|
we don't support C<$/> as undef (for slurping full content) and some of the other |
96
|
|
|
|
|
|
|
more esoteric values of C<$/> as the author percieves that support was not needed |
97
|
|
|
|
|
|
|
withing the context of adapting C for L uses (all exampled L |
98
|
|
|
|
|
|
|
handlers seemed to use the scalar ref fixed length chunk value for C<$/>, but |
99
|
|
|
|
|
|
|
we choose to also support the scalar record deliminator option since its very |
100
|
|
|
|
|
|
|
commonly seen elsewhere). |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
This middleware has the following attributes: |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head2 always_adapt |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
Defaults to false, Optional. |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Set this to any true value and the proxy will always wrap any filehandle like |
111
|
|
|
|
|
|
|
object, as long as it has a C method (even it if already has a C |
112
|
|
|
|
|
|
|
method.) Use this if you have a custom filehandle like object that you are using |
113
|
|
|
|
|
|
|
as the body of a L reponse that has both C and C but the |
114
|
|
|
|
|
|
|
C is broken in some way (but C isn't). |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=head2 chunksize |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
Defaults to 65536, Optional. |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
When adapting C, we call for chunks of data 65536 in length. This may not be the |
121
|
|
|
|
|
|
|
most efficient way to read your files based on your specific requirements. If so, you |
122
|
|
|
|
|
|
|
may override the size of the chunks: |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
builder { |
125
|
|
|
|
|
|
|
enable 'AdaptFilehandleRead', chunksize=>65536; |
126
|
|
|
|
|
|
|
$app; |
127
|
|
|
|
|
|
|
}; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
B: Be aware that the chunk is read into memory as each chunk is read. Should a |
130
|
|
|
|
|
|
|
chunk fail to find the deliminator indicated by C<$/>, another chunk would be read. |
131
|
|
|
|
|
|
|
If you entire file contains no match, it is not impossible for the entire file to be |
132
|
|
|
|
|
|
|
thus read into memory should C be used. In these cases you might wish to |
133
|
|
|
|
|
|
|
make sure your underlying L server has other ways to handle these types of |
134
|
|
|
|
|
|
|
files (for example using XSendfile or via some other optimization.) or instead be sure |
135
|
|
|
|
|
|
|
to use the fixed chunk sized option for C<$/>. |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
B: For most L handlers, "$/" is set to a scalar refer, such as: |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
local $/ = \'4096' |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
which is a flag indicating we'd prefer ->getline to return fixed length chunks |
142
|
|
|
|
|
|
|
instead of variable length lines. In this case the 'chunksize' attribute is |
143
|
|
|
|
|
|
|
ignored. Which means if you are using this with L chances are this |
144
|
|
|
|
|
|
|
attribute will not be respected :) You probably should not worry about this! |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head1 SEE ALSO |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
L, L, L, L, |
149
|
|
|
|
|
|
|
L. |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
See 'perlvar' docs for more on the possible values of C<$/>. |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=head1 AUTHOR |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
John Napiorkowski L |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Copyright 2014, John Napiorkowski L |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under |
162
|
|
|
|
|
|
|
the same terms as Perl itself. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=cut |