| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package STF::Dispatcher::PSGI; |
|
2
|
2
|
|
|
2
|
|
3146
|
use strict; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
121
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '1.12'; |
|
4
|
2
|
|
|
2
|
|
13
|
use Carp (); |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
34
|
|
|
5
|
2
|
|
|
2
|
|
1047
|
use HTTP::Date (); |
|
|
2
|
|
|
|
|
5069
|
|
|
|
2
|
|
|
|
|
46
|
|
|
6
|
2
|
|
|
2
|
|
324385
|
use Plack::Request; |
|
|
2
|
|
|
|
|
600187
|
|
|
|
2
|
|
|
|
|
78
|
|
|
7
|
2
|
|
|
2
|
|
5770
|
use Plack::Middleware::HTTPExceptions; |
|
|
2
|
|
|
|
|
24100
|
|
|
|
2
|
|
|
|
|
76
|
|
|
8
|
2
|
|
|
2
|
|
17
|
use Scalar::Util (); |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
34
|
|
|
9
|
2
|
|
|
2
|
|
1285
|
use STF::Dispatcher::PSGI::HTTPException; |
|
|
2
|
|
|
|
|
7
|
|
|
|
2
|
|
|
|
|
66
|
|
|
10
|
|
|
|
|
|
|
use Class::Accessor::Lite |
|
11
|
2
|
|
|
|
|
21
|
rw => [ qw(impl nosniff_header) ] |
|
12
|
2
|
|
|
2
|
|
895
|
; |
|
|
2
|
|
|
|
|
1289
|
|
|
13
|
|
|
|
|
|
|
use constant +{ |
|
14
|
2
|
|
|
|
|
8612
|
STF_REPLICATION_HEADER => 'X-STF-Replication-Count', |
|
15
|
|
|
|
|
|
|
STF_REPLICATION_HEADER_DEPRECATED => 'X-Replication-Count', |
|
16
|
|
|
|
|
|
|
STF_RECURSIVE_DELETE_HEADER => 'X-STF-Recursive-Delete', |
|
17
|
|
|
|
|
|
|
STF_CONSISTENCY_HEADER => "X-STF-Consistency", |
|
18
|
|
|
|
|
|
|
# XXX This below is should be deprecated. don't use |
|
19
|
|
|
|
|
|
|
STF_FORCE_MASTER_HEADER => "X-STF-Force-MasterDB", |
|
20
|
|
|
|
|
|
|
STF_DELETED_OBJECTS_HEADER => "X-STF-Deleted-Objects", |
|
21
|
|
|
|
|
|
|
STF_MOVE_OBJECT_HEADER => "X-STF-Move-Destination", |
|
22
|
|
|
|
|
|
|
STF_DEFAULT_REPLICATION_COUNT => 2, |
|
23
|
2
|
|
|
2
|
|
221
|
}; |
|
|
2
|
|
|
|
|
4
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub new { |
|
26
|
2
|
|
|
2
|
0
|
9
|
my ($class, %args) = @_; |
|
27
|
|
|
|
|
|
|
|
|
28
|
2
|
50
|
|
|
|
11
|
my $impl = $args{impl} or |
|
29
|
|
|
|
|
|
|
Carp::croak( "Required parameter 'impl' not specified" ); |
|
30
|
2
|
|
|
|
|
9
|
foreach my $method (qw(create_bucket get_bucket delete_bucket create_object get_object delete_object delete_bucket modify_object rename_object is_valid_object)) { |
|
31
|
20
|
50
|
|
|
|
111
|
$impl->can( $method ) or |
|
32
|
|
|
|
|
|
|
Carp::croak("$impl does not implement $method"); |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
2
|
|
|
|
|
20
|
bless { nosniff_header => 1, %args }, $class; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub to_app { |
|
39
|
2
|
|
|
2
|
1
|
5
|
my $self = shift; |
|
40
|
2
|
|
|
60
|
|
12
|
my $app = sub { $self->handle_psgi(@_) }; |
|
|
60
|
|
|
|
|
108427
|
|
|
41
|
2
|
|
|
|
|
30
|
$app = Plack::Middleware::HTTPExceptions->wrap( $app ); |
|
42
|
2
|
50
|
|
|
|
125
|
if ($self->nosniff_header) { |
|
43
|
2
|
|
|
|
|
1309
|
require Plack::Middleware::Header; |
|
44
|
2
|
|
|
|
|
717
|
$app = Plack::Middleware::Header->wrap( $app, |
|
45
|
|
|
|
|
|
|
set => [ 'X-Content-Type-Options' => 'nosniff' ] |
|
46
|
|
|
|
|
|
|
); |
|
47
|
|
|
|
|
|
|
} |
|
48
|
2
|
|
|
|
|
89
|
$app; |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub handle_psgi { |
|
52
|
60
|
|
|
60
|
0
|
147
|
my ($self, $env) = @_; |
|
53
|
|
|
|
|
|
|
|
|
54
|
60
|
|
|
|
|
254
|
my $guard = $self->impl->start_request( $env ); |
|
55
|
|
|
|
|
|
|
|
|
56
|
60
|
|
|
|
|
11052
|
my $req = Plack::Request->new($env); |
|
57
|
60
|
|
|
|
|
1023
|
my $res; |
|
58
|
60
|
|
|
|
|
133
|
my $method = $env->{REQUEST_METHOD}; |
|
59
|
60
|
100
|
|
|
|
411
|
if ($method =~ /^(?:GET|HEAD)$/) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
60
|
20
|
|
|
|
|
87
|
$res = $self->get_object( $req ); |
|
61
|
|
|
|
|
|
|
} elsif ($method eq 'PUT') { |
|
62
|
18
|
|
100
|
|
|
101
|
my $cl = $env->{CONTENT_LENGTH} || 0; |
|
63
|
18
|
100
|
|
|
|
48
|
if ( $cl == 0 ) { |
|
64
|
8
|
|
|
|
|
33
|
$res = $self->create_bucket( $req ); |
|
65
|
|
|
|
|
|
|
} else { |
|
66
|
10
|
|
|
|
|
53
|
$res = $self->create_object( $req ); |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
} elsif ($method eq 'DELETE') { |
|
69
|
10
|
|
|
|
|
46
|
$res = $self->delete_object( $req ); |
|
70
|
|
|
|
|
|
|
} elsif ($method eq 'POST') { |
|
71
|
2
|
|
|
|
|
9
|
$res = $self->modify_object( $req ); |
|
72
|
|
|
|
|
|
|
} elsif ($method eq 'MOVE') { |
|
73
|
10
|
|
|
|
|
37
|
$res = $self->rename_object( $req ); |
|
74
|
|
|
|
|
|
|
} else { |
|
75
|
0
|
|
|
|
|
0
|
$res = $req->new_response(400, [ "Content-Type" => "text/plain" ], [ "Bad Request" ]); |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
58
|
|
|
|
|
7528
|
return $res->finalize(); |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub parse_names { |
|
82
|
70
|
|
|
70
|
0
|
1327
|
my ($self, $path) = @_; |
|
83
|
70
|
50
|
|
|
|
415
|
if ( $path !~ m{^/([^/]+)(?:/(.+)$)?} ) { |
|
84
|
0
|
|
|
|
|
0
|
return (); |
|
85
|
|
|
|
|
|
|
} |
|
86
|
70
|
|
|
|
|
313
|
return ($1, $2); |
|
87
|
|
|
|
|
|
|
} |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub create_bucket { |
|
90
|
8
|
|
|
8
|
1
|
12
|
my ($self, $req) = @_; |
|
91
|
|
|
|
|
|
|
|
|
92
|
8
|
|
|
|
|
38
|
my ($bucket_name, $object_name) = $self->parse_names( $req->path ); |
|
93
|
8
|
100
|
|
|
|
81
|
if ( $object_name ) { |
|
94
|
2
|
|
|
|
|
16
|
return $req->new_response( 400, [], [ "Bad bucket name $bucket_name/$object_name" ] ); |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
6
|
|
|
|
|
23
|
my $bucket = $self->impl->get_bucket( { |
|
98
|
|
|
|
|
|
|
bucket_name => $bucket_name, |
|
99
|
|
|
|
|
|
|
request => $req, |
|
100
|
|
|
|
|
|
|
} ); |
|
101
|
6
|
100
|
|
|
|
46
|
if ($bucket) { |
|
102
|
2
|
|
|
|
|
12
|
return $req->new_response( 204, [], [] ); |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
4
|
|
|
|
|
12
|
$bucket = $self->impl->create_bucket( { |
|
106
|
|
|
|
|
|
|
bucket_name => $bucket_name, |
|
107
|
|
|
|
|
|
|
request => $req, |
|
108
|
|
|
|
|
|
|
} ); |
|
109
|
4
|
50
|
|
|
|
30
|
if (! $bucket) { |
|
110
|
0
|
|
|
|
|
0
|
return $req->new_response( 500, [], [ "Failed to create bucket" ] ); |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
4
|
|
|
|
|
36
|
return $req->new_response( 201, [], [ "Created bucket" ] ); |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub create_object { |
|
117
|
10
|
|
|
10
|
1
|
23
|
my ($self, $req) = @_; |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# find the appropriate bucket |
|
120
|
10
|
|
|
|
|
45
|
my ($bucket_name, $object_name) = $self->parse_names( $req->path ); |
|
121
|
10
|
|
|
|
|
43
|
my $bucket = $self->impl->get_bucket( { |
|
122
|
|
|
|
|
|
|
bucket_name => $bucket_name, |
|
123
|
|
|
|
|
|
|
request => $req |
|
124
|
|
|
|
|
|
|
} ); |
|
125
|
|
|
|
|
|
|
|
|
126
|
10
|
100
|
|
|
|
128
|
if (! $bucket) { |
|
127
|
|
|
|
|
|
|
# XXX Should be 403? |
|
128
|
2
|
|
|
|
|
14
|
return $req->new_response(500, ["Content-Type" => "text/plain"], [ "Failed to find bucket" ] ); |
|
129
|
|
|
|
|
|
|
} |
|
130
|
8
|
100
|
|
|
|
31
|
if (! $object_name) { |
|
131
|
2
|
|
|
|
|
13
|
return $req->new_response(400, [], ["Could not extract object name"]); |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# try to find a suffix |
|
135
|
6
|
|
|
|
|
25
|
my ($suffix) = ( $req->path =~ /\.([a-zA-Z0-9]+)$/ ); |
|
136
|
6
|
|
50
|
|
|
971
|
$suffix ||= 'dat'; |
|
137
|
|
|
|
|
|
|
|
|
138
|
6
|
|
|
|
|
73
|
my $input = $req->input; |
|
139
|
6
|
|
|
|
|
49
|
my $code; |
|
140
|
6
|
50
|
|
|
|
98
|
if ( $code = $input->can('rewind') ) { |
|
|
|
50
|
|
|
|
|
|
|
141
|
0
|
|
|
|
|
0
|
$code->( $input ); |
|
142
|
|
|
|
|
|
|
} elsif ( $code = $input->can('seek') ) { |
|
143
|
6
|
|
|
|
|
41
|
$code->( $input, 0, 0 ); |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
6
|
|
|
|
|
58
|
my %ext_args; |
|
147
|
6
|
50
|
|
|
|
31
|
if ($req->content_type) { |
|
148
|
6
|
|
|
|
|
67
|
$ext_args{content_type} = $req->content_type; |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
|
|
151
|
6
|
|
50
|
|
|
69
|
my $object = $self->impl->create_object( { |
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
152
|
|
|
|
|
|
|
bucket => $bucket, |
|
153
|
|
|
|
|
|
|
consistency => $req->header( STF_CONSISTENCY_HEADER ) || 0, |
|
154
|
|
|
|
|
|
|
object_name => $object_name, |
|
155
|
|
|
|
|
|
|
size => $req->content_length || 0, |
|
156
|
|
|
|
|
|
|
suffix => $suffix, |
|
157
|
|
|
|
|
|
|
input => $input, |
|
158
|
|
|
|
|
|
|
replicas => $req->header( STF_REPLICATION_HEADER ) || |
|
159
|
|
|
|
|
|
|
$req->header( STF_REPLICATION_HEADER_DEPRECATED ) || |
|
160
|
|
|
|
|
|
|
STF_DEFAULT_REPLICATION_COUNT || 0, |
|
161
|
|
|
|
|
|
|
request => $req, |
|
162
|
|
|
|
|
|
|
%ext_args |
|
163
|
|
|
|
|
|
|
} ); |
|
164
|
6
|
50
|
|
|
|
93
|
if (! $object) { |
|
165
|
0
|
|
|
|
|
0
|
return $req->new_response( 500, [], [ "Failed to create object" ] ); |
|
166
|
|
|
|
|
|
|
} |
|
167
|
6
|
|
|
|
|
54
|
return $req->new_response( 201, [], [ "Created " . $req->path ] ); |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub delete_object { |
|
171
|
10
|
|
|
10
|
1
|
17
|
my ($self, $req) = @_; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# find the appropriate bucket |
|
174
|
10
|
|
|
|
|
36
|
my ($bucket_name, $object_name) = $self->parse_names( $req->path ); |
|
175
|
10
|
|
|
|
|
40
|
my $bucket = $self->impl->get_bucket( { |
|
176
|
|
|
|
|
|
|
bucket_name => $bucket_name, |
|
177
|
|
|
|
|
|
|
request => $req |
|
178
|
|
|
|
|
|
|
} ); |
|
179
|
10
|
100
|
|
|
|
80
|
if (! $bucket) { |
|
180
|
4
|
100
|
|
|
|
11
|
if ( ! $object_name ) { |
|
181
|
2
|
|
|
|
|
14
|
return $req->new_response(404, ["Content-Type" => "text/plain"], [ "No such bucket" ] ); |
|
182
|
|
|
|
|
|
|
} else { |
|
183
|
2
|
|
|
|
|
13
|
return $req->new_response(500, ["Content-Type" => "text/plain"], [ "Failed to find bucket" ] ); |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# if there's no object_name, then this is a request to delete |
|
188
|
|
|
|
|
|
|
# the bucket, not an object |
|
189
|
6
|
100
|
|
|
|
20
|
if ( ! $object_name ) { |
|
190
|
2
|
|
50
|
|
|
11
|
my $ret = $self->impl->delete_bucket( { |
|
191
|
|
|
|
|
|
|
bucket => $bucket, |
|
192
|
|
|
|
|
|
|
recursive => $req->header( STF_RECURSIVE_DELETE_HEADER ) || 0, |
|
193
|
|
|
|
|
|
|
request => $req, |
|
194
|
|
|
|
|
|
|
} ); |
|
195
|
2
|
50
|
|
|
|
21
|
if (! $ret) { |
|
196
|
0
|
|
|
|
|
0
|
return $req->new_response(500, ["Content-Type" => "text/plain"], ["Failed to delete bucket" ]); |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
|
|
199
|
2
|
|
|
|
|
15
|
return $req->new_response( 204, [], [] ); |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
4
|
|
|
|
|
15
|
my $is_valid = $self->impl->is_valid_object( { |
|
203
|
|
|
|
|
|
|
bucket => $bucket, |
|
204
|
|
|
|
|
|
|
object_name => $object_name, |
|
205
|
|
|
|
|
|
|
request => $req, |
|
206
|
|
|
|
|
|
|
}); |
|
207
|
4
|
100
|
|
|
|
18
|
if (! $is_valid) { |
|
208
|
2
|
|
|
|
|
11
|
return $req->new_response(404, [], [ "No such object" ]); |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
|
|
211
|
2
|
50
|
|
|
|
9
|
if ($self->impl->delete_object( { |
|
212
|
|
|
|
|
|
|
bucket => $bucket, |
|
213
|
|
|
|
|
|
|
object_name => $object_name, |
|
214
|
|
|
|
|
|
|
request => $req, |
|
215
|
|
|
|
|
|
|
} )) { |
|
216
|
2
|
|
|
|
|
11
|
return $req->new_response( 204, [], [] ); |
|
217
|
|
|
|
|
|
|
} else { |
|
218
|
0
|
|
|
|
|
0
|
return $req->new_response( 500, [ "Content-Type" => "text/plain" ], [ "Failed to delete object" ] ); |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub get_object { |
|
223
|
20
|
|
|
20
|
1
|
40
|
my ($self, $req) = @_; |
|
224
|
|
|
|
|
|
|
# find the appropriate bucket |
|
225
|
20
|
|
|
|
|
77
|
my ($bucket_name, $object_name) = $self->parse_names( $req->path ); |
|
226
|
20
|
|
|
|
|
72
|
my $bucket = $self->impl->get_bucket( { |
|
227
|
|
|
|
|
|
|
bucket_name => $bucket_name, |
|
228
|
|
|
|
|
|
|
request => $req |
|
229
|
|
|
|
|
|
|
} ); |
|
230
|
20
|
100
|
|
|
|
145
|
if (! $bucket) { |
|
231
|
2
|
|
|
|
|
18
|
return $req->new_response(404, ["Content-Type" => "text/plain"], [ "Failed to find bucket" ] ); |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
|
|
234
|
18
|
|
50
|
|
|
72
|
my $object = $self->impl->get_object( { |
|
235
|
|
|
|
|
|
|
bucket => $bucket, |
|
236
|
|
|
|
|
|
|
object_name => $object_name, |
|
237
|
|
|
|
|
|
|
request => $req, |
|
238
|
|
|
|
|
|
|
force_master => $req->header( STF_FORCE_MASTER_HEADER ) || 0, |
|
239
|
|
|
|
|
|
|
} ); |
|
240
|
16
|
100
|
|
|
|
295
|
if (! $object) { |
|
241
|
6
|
|
|
|
|
33
|
return $req->new_response( 404, [], [ "Failed to get object" ] ); |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
10
|
|
|
|
|
18
|
my @headers; |
|
245
|
10
|
50
|
|
|
|
75
|
if ( my $ct = $object->can('content_type') ) { |
|
246
|
10
|
|
|
|
|
37
|
push @headers, "Content-Type", $object->content_type; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
10
|
50
|
|
|
|
118
|
if ( my $lm = $object->can('modified_on') ) { |
|
249
|
10
|
|
|
|
|
36
|
push @headers, "Last-Modified", HTTP::Date::time2str($object->modified_on); |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
10
|
100
|
|
|
|
290
|
return $req->new_response( 200, |
|
253
|
|
|
|
|
|
|
\@headers, |
|
254
|
|
|
|
|
|
|
[ $req->method eq 'HEAD' ? '' : $object->content ] |
|
255
|
|
|
|
|
|
|
); |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
sub modify_object { |
|
259
|
2
|
|
|
2
|
1
|
5
|
my ($self, $req) = @_; |
|
260
|
|
|
|
|
|
|
|
|
261
|
2
|
|
|
|
|
9
|
my ($bucket_name, $object_name) = $self->parse_names( $req->path ); |
|
262
|
2
|
|
|
|
|
9
|
my $bucket = $self->impl->get_bucket( { |
|
263
|
|
|
|
|
|
|
bucket_name => $bucket_name, |
|
264
|
|
|
|
|
|
|
request => $req |
|
265
|
|
|
|
|
|
|
} ); |
|
266
|
2
|
50
|
|
|
|
16
|
if (! $bucket) { |
|
267
|
0
|
|
|
|
|
0
|
return $req->new_response(500, ["Content-Type" => "text/plain"], [ "Failed to find bucket" ] ); |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
|
|
270
|
2
|
|
|
|
|
8
|
my $is_valid = $self->impl->is_valid_object( { |
|
271
|
|
|
|
|
|
|
bucket => $bucket, |
|
272
|
|
|
|
|
|
|
object_name => $object_name, |
|
273
|
|
|
|
|
|
|
request => $req, |
|
274
|
|
|
|
|
|
|
}); |
|
275
|
2
|
50
|
|
|
|
12
|
if (! $is_valid) { |
|
276
|
0
|
|
|
|
|
0
|
return $req->new_response(404, [], [ "No such object" ]); |
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
2
|
|
50
|
|
|
9
|
my $ret = $self->impl->modify_object( { |
|
280
|
|
|
|
|
|
|
bucket => $bucket, |
|
281
|
|
|
|
|
|
|
object_name => $object_name, |
|
282
|
|
|
|
|
|
|
replicas => $req->header( STF_REPLICATION_HEADER ) || |
|
283
|
|
|
|
|
|
|
$req->header( STF_REPLICATION_HEADER_DEPRECATED ) || |
|
284
|
|
|
|
|
|
|
STF_DEFAULT_REPLICATION_COUNT || 0, |
|
285
|
|
|
|
|
|
|
request => $req, |
|
286
|
|
|
|
|
|
|
} ); |
|
287
|
|
|
|
|
|
|
|
|
288
|
2
|
50
|
|
|
|
11
|
if ($ret) { |
|
289
|
2
|
|
|
|
|
9
|
return $req->new_response(204, [], []); |
|
290
|
|
|
|
|
|
|
} else { |
|
291
|
0
|
|
|
|
|
0
|
return $req->new_response(500, ["Content-Type" => "text/plain"], [ "Failed to modify object" ]); |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
} |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub rename_object { |
|
296
|
10
|
|
|
10
|
0
|
16
|
my ($self, $req) = @_; |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# source |
|
299
|
10
|
|
|
|
|
38
|
my ($bucket_name, $object_name) = $self->parse_names( $req->path ); |
|
300
|
10
|
|
|
|
|
36
|
my $bucket = $self->impl->get_bucket( { |
|
301
|
|
|
|
|
|
|
bucket_name => $bucket_name, |
|
302
|
|
|
|
|
|
|
request => $req |
|
303
|
|
|
|
|
|
|
} ); |
|
304
|
10
|
50
|
|
|
|
75
|
if (! $bucket) { |
|
305
|
|
|
|
|
|
|
# XXX should be 403? |
|
306
|
0
|
|
|
|
|
0
|
return $req->new_response(500, ["Content-Type" => "text/plain"], [ "Failed to find source bucket" ] ); |
|
307
|
|
|
|
|
|
|
} |
|
308
|
|
|
|
|
|
|
|
|
309
|
10
|
100
|
|
|
|
32
|
if (! $object_name) { |
|
310
|
4
|
|
|
|
|
17
|
my ($dest_bucket, $dest_object) = $self->parse_names( $req->header( STF_MOVE_OBJECT_HEADER ) ); |
|
311
|
4
|
50
|
|
|
|
14
|
if (! $dest_bucket) { |
|
312
|
0
|
|
|
|
|
0
|
return $req->new_response(500, ["Content-Type" => "text/plain"], ["Destination bucket name was not specified"]); |
|
313
|
|
|
|
|
|
|
} |
|
314
|
4
|
50
|
|
|
|
12
|
if ($dest_object) { |
|
315
|
0
|
|
|
|
|
0
|
return $req->new_response(500, ["Content-Type" => "text/plain"], ["Destination contains object name"]); |
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
|
|
318
|
4
|
|
|
|
|
17
|
my $ok = $self->impl->rename_bucket({ |
|
319
|
|
|
|
|
|
|
bucket => $bucket, |
|
320
|
|
|
|
|
|
|
name => $dest_bucket |
|
321
|
|
|
|
|
|
|
}); |
|
322
|
4
|
100
|
|
|
|
187
|
if ($ok) { |
|
323
|
2
|
|
|
|
|
16
|
return $req->new_response(201, [], ["Moved"]); |
|
324
|
|
|
|
|
|
|
} else { |
|
325
|
2
|
|
|
|
|
11
|
return $req->new_response(500, [], ["Failed to rename bucket"]); |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
|
|
329
|
6
|
|
|
|
|
23
|
my $is_valid = $self->impl->is_valid_object( { |
|
330
|
|
|
|
|
|
|
bucket => $bucket, |
|
331
|
|
|
|
|
|
|
object_name => $object_name, |
|
332
|
|
|
|
|
|
|
request => $req, |
|
333
|
|
|
|
|
|
|
}); |
|
334
|
6
|
50
|
|
|
|
28
|
if (! $is_valid) { |
|
335
|
0
|
|
|
|
|
0
|
return $req->new_response(404, [], [ "No such source object" ]); |
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
|
|
339
|
6
|
|
|
|
|
26
|
my $destination = $req->header( STF_MOVE_OBJECT_HEADER ); |
|
340
|
6
|
|
|
|
|
1202
|
my ($dest_bucket_name, $dest_object_name) = $self->parse_names( $destination ); |
|
341
|
6
|
|
|
|
|
9
|
my $dest_bucket; |
|
342
|
6
|
100
|
|
|
|
20
|
if ( $dest_bucket_name eq $bucket_name ) { |
|
343
|
2
|
|
|
|
|
4
|
$dest_bucket = $bucket |
|
344
|
|
|
|
|
|
|
} else { |
|
345
|
4
|
|
|
|
|
14
|
$dest_bucket = $self->impl->get_bucket( { |
|
346
|
|
|
|
|
|
|
bucket_name => $dest_bucket_name, |
|
347
|
|
|
|
|
|
|
request => $req |
|
348
|
|
|
|
|
|
|
} ); |
|
349
|
4
|
100
|
|
|
|
28
|
if (! $dest_bucket) { |
|
350
|
|
|
|
|
|
|
# XXX should be 403? |
|
351
|
2
|
|
|
|
|
13
|
return $req->new_response(500, ["Content-Type" => "text/plain"], [ "Failed to find source bucket" ] ); |
|
352
|
|
|
|
|
|
|
} |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
|
|
355
|
4
|
|
|
|
|
17
|
my $rv = $self->impl->rename_object( { |
|
356
|
|
|
|
|
|
|
source_bucket => $bucket, |
|
357
|
|
|
|
|
|
|
source_object_name => $object_name, |
|
358
|
|
|
|
|
|
|
destination_bucket => $dest_bucket, |
|
359
|
|
|
|
|
|
|
destination_object_name => $dest_object_name, |
|
360
|
|
|
|
|
|
|
} ); |
|
361
|
|
|
|
|
|
|
|
|
362
|
4
|
50
|
|
|
|
27
|
if (! $rv) { |
|
363
|
0
|
|
|
|
|
0
|
return $req->new_response( 500, [], [ "Failed to create object" ] ); |
|
364
|
|
|
|
|
|
|
} |
|
365
|
4
|
|
|
|
|
20
|
return $req->new_response( 201, [], [ "Created " . $req->path ] ); |
|
366
|
|
|
|
|
|
|
} |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
1; |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
__END__ |