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__ |