001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.hadoop.fs.http.server; 020 021 import org.apache.hadoop.conf.Configuration; 022 import org.apache.hadoop.fs.FileSystem; 023 import org.apache.hadoop.fs.http.client.HttpFSFileSystem; 024 import org.apache.hadoop.fs.http.server.HttpFSParams.AccessTimeParam; 025 import org.apache.hadoop.fs.http.server.HttpFSParams.BlockSizeParam; 026 import org.apache.hadoop.fs.http.server.HttpFSParams.DataParam; 027 import org.apache.hadoop.fs.http.server.HttpFSParams.DeleteOpParam; 028 import org.apache.hadoop.fs.http.server.HttpFSParams.DeleteRecursiveParam; 029 import org.apache.hadoop.fs.http.server.HttpFSParams.DoAsParam; 030 import org.apache.hadoop.fs.http.server.HttpFSParams.FilterParam; 031 import org.apache.hadoop.fs.http.server.HttpFSParams.FsPathParam; 032 import org.apache.hadoop.fs.http.server.HttpFSParams.GetOpParam; 033 import org.apache.hadoop.fs.http.server.HttpFSParams.GroupParam; 034 import org.apache.hadoop.fs.http.server.HttpFSParams.LenParam; 035 import org.apache.hadoop.fs.http.server.HttpFSParams.ModifiedTimeParam; 036 import org.apache.hadoop.fs.http.server.HttpFSParams.OffsetParam; 037 import org.apache.hadoop.fs.http.server.HttpFSParams.OverwriteParam; 038 import org.apache.hadoop.fs.http.server.HttpFSParams.OwnerParam; 039 import org.apache.hadoop.fs.http.server.HttpFSParams.PermissionParam; 040 import org.apache.hadoop.fs.http.server.HttpFSParams.PostOpParam; 041 import org.apache.hadoop.fs.http.server.HttpFSParams.PutOpParam; 042 import org.apache.hadoop.fs.http.server.HttpFSParams.ReplicationParam; 043 import org.apache.hadoop.fs.http.server.HttpFSParams.ToPathParam; 044 import org.apache.hadoop.lib.service.FileSystemAccess; 045 import org.apache.hadoop.lib.service.FileSystemAccessException; 046 import org.apache.hadoop.lib.service.Groups; 047 import org.apache.hadoop.lib.service.Instrumentation; 048 import org.apache.hadoop.lib.service.ProxyUser; 049 import org.apache.hadoop.lib.servlet.FileSystemReleaseFilter; 050 import org.apache.hadoop.lib.servlet.HostnameFilter; 051 import org.apache.hadoop.lib.wsrs.InputStreamEntity; 052 import org.json.simple.JSONObject; 053 import org.slf4j.Logger; 054 import org.slf4j.LoggerFactory; 055 import org.slf4j.MDC; 056 057 import javax.ws.rs.Consumes; 058 import javax.ws.rs.DELETE; 059 import javax.ws.rs.DefaultValue; 060 import javax.ws.rs.GET; 061 import javax.ws.rs.POST; 062 import javax.ws.rs.PUT; 063 import javax.ws.rs.Path; 064 import javax.ws.rs.PathParam; 065 import javax.ws.rs.Produces; 066 import javax.ws.rs.QueryParam; 067 import javax.ws.rs.core.Context; 068 import javax.ws.rs.core.MediaType; 069 import javax.ws.rs.core.Response; 070 import javax.ws.rs.core.UriBuilder; 071 import javax.ws.rs.core.UriInfo; 072 import java.io.IOException; 073 import java.io.InputStream; 074 import java.net.URI; 075 import java.security.AccessControlException; 076 import java.security.Principal; 077 import java.text.MessageFormat; 078 import java.util.List; 079 import java.util.Map; 080 081 /** 082 * Main class of HttpFSServer server. 083 * <p/> 084 * The <code>HttpFSServer</code> class uses Jersey JAX-RS to binds HTTP requests to the 085 * different operations. 086 */ 087 @Path(HttpFSFileSystem.SERVICE_VERSION) 088 public class HttpFSServer { 089 private static Logger AUDIT_LOG = LoggerFactory.getLogger("httpfsaudit"); 090 091 /** 092 * Special binding for '/' as it is not handled by the wildcard binding. 093 * 094 * @param user principal making the request. 095 * @param op GET operation, default value is @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.GetOpValues#OPEN}. 096 * @param filter Glob filter, default value is none. Used only if the 097 * operation is @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.GetOpValues#LISTSTATUS} 098 * @param doAs user being impersonated, defualt value is none. It can be used 099 * only if the current user is a HttpFSServer proxyuser. 100 * 101 * @return the request response 102 * 103 * @throws IOException thrown if an IO error occurred. Thrown exceptions are 104 * handled by {@link HttpFSExceptionProvider}. 105 * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown 106 * exceptions are handled by {@link HttpFSExceptionProvider}. 107 */ 108 @GET 109 @Path("/") 110 @Produces(MediaType.APPLICATION_JSON) 111 public Response root(@Context Principal user, 112 @QueryParam(GetOpParam.NAME) GetOpParam op, 113 @QueryParam(FilterParam.NAME) @DefaultValue(FilterParam.DEFAULT) FilterParam filter, 114 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) DoAsParam doAs) 115 throws IOException, FileSystemAccessException { 116 return get(user, new FsPathParam(""), op, new OffsetParam(OffsetParam.DEFAULT), 117 new LenParam(LenParam.DEFAULT), filter, doAs, 118 new OverwriteParam(OverwriteParam.DEFAULT), 119 new BlockSizeParam(BlockSizeParam.DEFAULT), 120 new PermissionParam(PermissionParam.DEFAULT), 121 new ReplicationParam(ReplicationParam.DEFAULT)); 122 } 123 124 /** 125 * Resolves the effective user that will be used to request a FileSystemAccess filesystem. 126 * <p/> 127 * If the doAs-user is NULL or the same as the user, it returns the user. 128 * <p/> 129 * Otherwise it uses proxyuser rules (see {@link ProxyUser} to determine if the 130 * current user can impersonate the doAs-user. 131 * <p/> 132 * If the current user cannot impersonate the doAs-user an 133 * <code>AccessControlException</code> will be thrown. 134 * 135 * @param user principal for whom the filesystem instance is. 136 * @param doAs do-as user, if any. 137 * 138 * @return the effective user. 139 * 140 * @throws IOException thrown if an IO error occurrs. 141 * @throws AccessControlException thrown if the current user cannot impersonate 142 * the doAs-user. 143 */ 144 private String getEffectiveUser(Principal user, String doAs) throws IOException { 145 String effectiveUser = user.getName(); 146 if (doAs != null && !doAs.equals(user.getName())) { 147 ProxyUser proxyUser = HttpFSServerWebApp.get().get(ProxyUser.class); 148 proxyUser.validate(user.getName(), HostnameFilter.get(), doAs); 149 effectiveUser = doAs; 150 AUDIT_LOG.info("Proxy user [{}] DoAs user [{}]", user.getName(), doAs); 151 } 152 return effectiveUser; 153 } 154 155 /** 156 * Executes a {@link FileSystemAccess.FileSystemExecutor} using a filesystem for the effective 157 * user. 158 * 159 * @param user principal making the request. 160 * @param doAs do-as user, if any. 161 * @param executor FileSystemExecutor to execute. 162 * 163 * @return FileSystemExecutor response 164 * 165 * @throws IOException thrown if an IO error occurrs. 166 * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown 167 * exceptions are handled by {@link HttpFSExceptionProvider}. 168 */ 169 private <T> T fsExecute(Principal user, String doAs, FileSystemAccess.FileSystemExecutor<T> executor) 170 throws IOException, FileSystemAccessException { 171 String hadoopUser = getEffectiveUser(user, doAs); 172 FileSystemAccess fsAccess = HttpFSServerWebApp.get().get(FileSystemAccess.class); 173 Configuration conf = HttpFSServerWebApp.get().get(FileSystemAccess.class).getFileSystemConfiguration(); 174 return fsAccess.execute(hadoopUser, conf, executor); 175 } 176 177 /** 178 * Returns a filesystem instance. The fileystem instance is wired for release at the completion of 179 * the current Servlet request via the {@link FileSystemReleaseFilter}. 180 * <p/> 181 * If a do-as user is specified, the current user must be a valid proxyuser, otherwise an 182 * <code>AccessControlException</code> will be thrown. 183 * 184 * @param user principal for whom the filesystem instance is. 185 * @param doAs do-as user, if any. 186 * 187 * @return a filesystem for the specified user or do-as user. 188 * 189 * @throws IOException thrown if an IO error occurred. Thrown exceptions are 190 * handled by {@link HttpFSExceptionProvider}. 191 * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown 192 * exceptions are handled by {@link HttpFSExceptionProvider}. 193 */ 194 private FileSystem createFileSystem(Principal user, String doAs) throws IOException, FileSystemAccessException { 195 String hadoopUser = getEffectiveUser(user, doAs); 196 FileSystemAccess fsAccess = HttpFSServerWebApp.get().get(FileSystemAccess.class); 197 Configuration conf = HttpFSServerWebApp.get().get(FileSystemAccess.class).getFileSystemConfiguration(); 198 FileSystem fs = fsAccess.createFileSystem(hadoopUser, conf); 199 FileSystemReleaseFilter.setFileSystem(fs); 200 return fs; 201 } 202 203 /** 204 * Binding to handle all GET requests, supported operations are 205 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.GetOpValues}. 206 * <p/> 207 * The @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.GetOpValues#INSTRUMENTATION} operation is available only 208 * to users that are in HttpFSServer's admin group (see {@link HttpFSServer}. It returns 209 * HttpFSServer instrumentation data. The specified path must be '/'. 210 * 211 * @param user principal making the request. 212 * @param path path for the GET request. 213 * @param op GET operation, default value is @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.GetOpValues#OPEN}. 214 * @param offset of the file being fetch, used only with 215 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.GetOpValues#OPEN} operations. 216 * @param len amounts of bytes, used only with @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.GetOpValues#OPEN} 217 * operations. 218 * @param filter Glob filter, default value is none. Used only if the 219 * operation is @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.GetOpValues#LISTSTATUS} 220 * @param doAs user being impersonated, defualt value is none. It can be used 221 * only if the current user is a HttpFSServer proxyuser. 222 * @param override default is true. Used only for 223 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#CREATE} operations. 224 * @param blockSize block size to set, used only by 225 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#CREATE} operations. 226 * @param permission permission to set, used only by 227 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETPERMISSION}. 228 * @param replication replication factor to set, used only by 229 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETREPLICATION}. 230 * 231 * @return the request response. 232 * 233 * @throws IOException thrown if an IO error occurred. Thrown exceptions are 234 * handled by {@link HttpFSExceptionProvider}. 235 * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown 236 * exceptions are handled by {@link HttpFSExceptionProvider}. 237 */ 238 @GET 239 @Path("{path:.*}") 240 @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) 241 public Response get(@Context Principal user, 242 @PathParam("path") @DefaultValue("") FsPathParam path, 243 @QueryParam(GetOpParam.NAME) GetOpParam op, 244 @QueryParam(OffsetParam.NAME) @DefaultValue(OffsetParam.DEFAULT) OffsetParam offset, 245 @QueryParam(LenParam.NAME) @DefaultValue(LenParam.DEFAULT) LenParam len, 246 @QueryParam(FilterParam.NAME) @DefaultValue(FilterParam.DEFAULT) FilterParam filter, 247 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) DoAsParam doAs, 248 249 //these params are only for createHandle operation acceptance purposes 250 @QueryParam(OverwriteParam.NAME) @DefaultValue(OverwriteParam.DEFAULT) OverwriteParam override, 251 @QueryParam(BlockSizeParam.NAME) @DefaultValue(BlockSizeParam.DEFAULT) BlockSizeParam blockSize, 252 @QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT) 253 PermissionParam permission, 254 @QueryParam(ReplicationParam.NAME) @DefaultValue(ReplicationParam.DEFAULT) 255 ReplicationParam replication 256 ) 257 throws IOException, FileSystemAccessException { 258 Response response = null; 259 if (op == null) { 260 throw new UnsupportedOperationException(MessageFormat.format("Missing [{0}] parameter", GetOpParam.NAME)); 261 } else { 262 path.makeAbsolute(); 263 MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name()); 264 switch (op.value()) { 265 case OPEN: { 266 //Invoking the command directly using an unmanaged FileSystem that is released by the 267 //FileSystemReleaseFilter 268 FSOperations.FSOpen command = new FSOperations.FSOpen(path.value()); 269 FileSystem fs = createFileSystem(user, doAs.value()); 270 InputStream is = command.execute(fs); 271 AUDIT_LOG.info("[{}] offset [{}] len [{}]", new Object[]{path, offset, len}); 272 InputStreamEntity entity = new InputStreamEntity(is, offset.value(), len.value()); 273 response = Response.ok(entity).type(MediaType.APPLICATION_OCTET_STREAM).build(); 274 break; 275 } 276 case GETFILESTATUS: { 277 FSOperations.FSFileStatus command = new FSOperations.FSFileStatus(path.value()); 278 Map json = fsExecute(user, doAs.value(), command); 279 AUDIT_LOG.info("[{}]", path); 280 response = Response.ok(json).type(MediaType.APPLICATION_JSON).build(); 281 break; 282 } 283 case LISTSTATUS: { 284 FSOperations.FSListStatus command = new FSOperations.FSListStatus(path.value(), filter.value()); 285 Map json = fsExecute(user, doAs.value(), command); 286 if (filter.value() == null) { 287 AUDIT_LOG.info("[{}]", path); 288 } else { 289 AUDIT_LOG.info("[{}] filter [{}]", path, filter.value()); 290 } 291 response = Response.ok(json).type(MediaType.APPLICATION_JSON).build(); 292 break; 293 } 294 case GETHOMEDIRECTORY: { 295 FSOperations.FSHomeDir command = new FSOperations.FSHomeDir(); 296 JSONObject json = fsExecute(user, doAs.value(), command); 297 AUDIT_LOG.info(""); 298 response = Response.ok(json).type(MediaType.APPLICATION_JSON).build(); 299 break; 300 } 301 case INSTRUMENTATION: { 302 if (!path.value().equals("/")) { 303 throw new UnsupportedOperationException( 304 MessageFormat.format("Invalid path for {0}={1}, must be '/'", 305 GetOpParam.NAME, HttpFSFileSystem.GetOpValues.INSTRUMENTATION)); 306 } 307 Groups groups = HttpFSServerWebApp.get().get(Groups.class); 308 List<String> userGroups = groups.getGroups(user.getName()); 309 if (!userGroups.contains(HttpFSServerWebApp.get().getAdminGroup())) { 310 throw new AccessControlException("User not in HttpFSServer admin group"); 311 } 312 Instrumentation instrumentation = HttpFSServerWebApp.get().get(Instrumentation.class); 313 Map snapshot = instrumentation.getSnapshot(); 314 response = Response.ok(snapshot).build(); 315 break; 316 } 317 case GETCONTENTSUMMARY: { 318 FSOperations.FSContentSummary command = new FSOperations.FSContentSummary(path.value()); 319 Map json = fsExecute(user, doAs.value(), command); 320 AUDIT_LOG.info("[{}]", path); 321 response = Response.ok(json).type(MediaType.APPLICATION_JSON).build(); 322 break; 323 } 324 case GETFILECHECKSUM: { 325 FSOperations.FSFileChecksum command = new FSOperations.FSFileChecksum(path.value()); 326 Map json = fsExecute(user, doAs.value(), command); 327 AUDIT_LOG.info("[{}]", path); 328 response = Response.ok(json).type(MediaType.APPLICATION_JSON).build(); 329 break; 330 } 331 case GETDELEGATIONTOKEN: { 332 response = Response.status(Response.Status.BAD_REQUEST).build(); 333 break; 334 } 335 case GETFILEBLOCKLOCATIONS: { 336 response = Response.status(Response.Status.BAD_REQUEST).build(); 337 break; 338 } 339 } 340 return response; 341 } 342 } 343 344 /** 345 * Creates the URL for an upload operation (create or append). 346 * 347 * @param uriInfo uri info of the request. 348 * @param uploadOperation operation for the upload URL. 349 * 350 * @return the URI for uploading data. 351 */ 352 protected URI createUploadRedirectionURL(UriInfo uriInfo, Enum<?> uploadOperation) { 353 UriBuilder uriBuilder = uriInfo.getRequestUriBuilder(); 354 uriBuilder = uriBuilder.replaceQueryParam(PutOpParam.NAME, uploadOperation). 355 queryParam(DataParam.NAME, Boolean.TRUE); 356 return uriBuilder.build(null); 357 } 358 359 /** 360 * Binding to handle all DELETE requests. 361 * 362 * @param user principal making the request. 363 * @param path path for the DELETE request. 364 * @param op DELETE operation, default value is @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.DeleteOpValues#DELETE}. 365 * @param recursive indicates if the delete is recursive, default is <code>false</code> 366 * @param doAs user being impersonated, defualt value is none. It can be used 367 * only if the current user is a HttpFSServer proxyuser. 368 * 369 * @return the request response. 370 * 371 * @throws IOException thrown if an IO error occurred. Thrown exceptions are 372 * handled by {@link HttpFSExceptionProvider}. 373 * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown 374 * exceptions are handled by {@link HttpFSExceptionProvider}. 375 */ 376 @DELETE 377 @Path("{path:.*}") 378 @Produces(MediaType.APPLICATION_JSON) 379 public Response delete(@Context Principal user, 380 @PathParam("path") FsPathParam path, 381 @QueryParam(DeleteOpParam.NAME) DeleteOpParam op, 382 @QueryParam(DeleteRecursiveParam.NAME) @DefaultValue(DeleteRecursiveParam.DEFAULT) 383 DeleteRecursiveParam recursive, 384 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) DoAsParam doAs) 385 throws IOException, FileSystemAccessException { 386 Response response = null; 387 if (op == null) { 388 throw new UnsupportedOperationException(MessageFormat.format("Missing [{0}] parameter", DeleteOpParam.NAME)); 389 } 390 switch (op.value()) { 391 case DELETE: { 392 path.makeAbsolute(); 393 MDC.put(HttpFSFileSystem.OP_PARAM, "DELETE"); 394 AUDIT_LOG.info("[{}] recursive [{}]", path, recursive); 395 FSOperations.FSDelete command = new FSOperations.FSDelete(path.value(), recursive.value()); 396 JSONObject json = fsExecute(user, doAs.value(), command); 397 response = Response.ok(json).type(MediaType.APPLICATION_JSON).build(); 398 break; 399 } 400 } 401 return response; 402 } 403 404 405 /** 406 * Binding to handle all PUT requests, supported operations are 407 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues}. 408 * 409 * @param is request input stream, used only for 410 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PostOpValues#APPEND} operations. 411 * @param user principal making the request. 412 * @param uriInfo the request uriInfo. 413 * @param path path for the PUT request. 414 * @param op PUT operation, no default value. 415 * @param toPath new path, used only for 416 * {@link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#RENAME} operations. 417 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETTIMES}. 418 * @param owner owner to set, used only for 419 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETOWNER} operations. 420 * @param group group to set, used only for 421 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETOWNER} operations. 422 * @param override default is true. Used only for 423 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#CREATE} operations. 424 * @param blockSize block size to set, used only by 425 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#CREATE} operations. 426 * @param permission permission to set, used only by 427 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETPERMISSION}. 428 * @param replication replication factor to set, used only by 429 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETREPLICATION}. 430 * @param modifiedTime modified time, in seconds since EPOC, used only by 431 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETTIMES}. 432 * @param accessTime accessed time, in seconds since EPOC, used only by 433 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PutOpValues#SETTIMES}. 434 * @param hasData indicates if the append request is uploading data or not 435 * (just getting the handle). 436 * @param doAs user being impersonated, defualt value is none. It can be used 437 * only if the current user is a HttpFSServer proxyuser. 438 * 439 * @return the request response. 440 * 441 * @throws IOException thrown if an IO error occurred. Thrown exceptions are 442 * handled by {@link HttpFSExceptionProvider}. 443 * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown 444 * exceptions are handled by {@link HttpFSExceptionProvider}. 445 */ 446 @PUT 447 @Path("{path:.*}") 448 @Consumes({"*/*"}) 449 @Produces({MediaType.APPLICATION_JSON}) 450 public Response put(InputStream is, 451 @Context Principal user, 452 @Context UriInfo uriInfo, 453 @PathParam("path") FsPathParam path, 454 @QueryParam(PutOpParam.NAME) PutOpParam op, 455 @QueryParam(ToPathParam.NAME) @DefaultValue(ToPathParam.DEFAULT) ToPathParam toPath, 456 @QueryParam(OwnerParam.NAME) @DefaultValue(OwnerParam.DEFAULT) OwnerParam owner, 457 @QueryParam(GroupParam.NAME) @DefaultValue(GroupParam.DEFAULT) GroupParam group, 458 @QueryParam(OverwriteParam.NAME) @DefaultValue(OverwriteParam.DEFAULT) OverwriteParam override, 459 @QueryParam(BlockSizeParam.NAME) @DefaultValue(BlockSizeParam.DEFAULT) BlockSizeParam blockSize, 460 @QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT) 461 PermissionParam permission, 462 @QueryParam(ReplicationParam.NAME) @DefaultValue(ReplicationParam.DEFAULT) 463 ReplicationParam replication, 464 @QueryParam(ModifiedTimeParam.NAME) @DefaultValue(ModifiedTimeParam.DEFAULT) 465 ModifiedTimeParam modifiedTime, 466 @QueryParam(AccessTimeParam.NAME) @DefaultValue(AccessTimeParam.DEFAULT) 467 AccessTimeParam accessTime, 468 @QueryParam(DataParam.NAME) @DefaultValue(DataParam.DEFAULT) DataParam hasData, 469 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) DoAsParam doAs) 470 throws IOException, FileSystemAccessException { 471 Response response = null; 472 if (op == null) { 473 throw new UnsupportedOperationException(MessageFormat.format("Missing [{0}] parameter", PutOpParam.NAME)); 474 } 475 path.makeAbsolute(); 476 MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name()); 477 switch (op.value()) { 478 case CREATE: { 479 if (!hasData.value()) { 480 response = Response.temporaryRedirect( 481 createUploadRedirectionURL(uriInfo, HttpFSFileSystem.PutOpValues.CREATE)).build(); 482 } else { 483 FSOperations.FSCreate 484 command = new FSOperations.FSCreate(is, path.value(), permission.value(), override.value(), 485 replication.value(), blockSize.value()); 486 fsExecute(user, doAs.value(), command); 487 AUDIT_LOG.info("[{}] permission [{}] override [{}] replication [{}] blockSize [{}]", 488 new Object[]{path, permission, override, replication, blockSize}); 489 response = Response.status(Response.Status.CREATED).build(); 490 } 491 break; 492 } 493 case MKDIRS: { 494 FSOperations.FSMkdirs command = new FSOperations.FSMkdirs(path.value(), permission.value()); 495 JSONObject json = fsExecute(user, doAs.value(), command); 496 AUDIT_LOG.info("[{}] permission [{}]", path, permission.value()); 497 response = Response.ok(json).type(MediaType.APPLICATION_JSON).build(); 498 break; 499 } 500 case RENAME: { 501 FSOperations.FSRename command = new FSOperations.FSRename(path.value(), toPath.value()); 502 JSONObject json = fsExecute(user, doAs.value(), command); 503 AUDIT_LOG.info("[{}] to [{}]", path, toPath); 504 response = Response.ok(json).type(MediaType.APPLICATION_JSON).build(); 505 break; 506 } 507 case SETOWNER: { 508 FSOperations.FSSetOwner command = new FSOperations.FSSetOwner(path.value(), owner.value(), group.value()); 509 fsExecute(user, doAs.value(), command); 510 AUDIT_LOG.info("[{}] to (O/G)[{}]", path, owner.value() + ":" + group.value()); 511 response = Response.ok().build(); 512 break; 513 } 514 case SETPERMISSION: { 515 FSOperations.FSSetPermission command = new FSOperations.FSSetPermission(path.value(), permission.value()); 516 fsExecute(user, doAs.value(), command); 517 AUDIT_LOG.info("[{}] to [{}]", path, permission.value()); 518 response = Response.ok().build(); 519 break; 520 } 521 case SETREPLICATION: { 522 FSOperations.FSSetReplication command = new FSOperations.FSSetReplication(path.value(), replication.value()); 523 JSONObject json = fsExecute(user, doAs.value(), command); 524 AUDIT_LOG.info("[{}] to [{}]", path, replication.value()); 525 response = Response.ok(json).build(); 526 break; 527 } 528 case SETTIMES: { 529 FSOperations.FSSetTimes 530 command = new FSOperations.FSSetTimes(path.value(), modifiedTime.value(), accessTime.value()); 531 fsExecute(user, doAs.value(), command); 532 AUDIT_LOG.info("[{}] to (M/A)[{}]", path, modifiedTime.value() + ":" + accessTime.value()); 533 response = Response.ok().build(); 534 break; 535 } 536 case RENEWDELEGATIONTOKEN: { 537 response = Response.status(Response.Status.BAD_REQUEST).build(); 538 break; 539 } 540 case CANCELDELEGATIONTOKEN: { 541 response = Response.status(Response.Status.BAD_REQUEST).build(); 542 break; 543 } 544 } 545 return response; 546 } 547 548 /** 549 * Binding to handle all OPST requests, supported operations are 550 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PostOpValues}. 551 * 552 * @param is request input stream, used only for 553 * @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PostOpValues#APPEND} operations. 554 * @param user principal making the request. 555 * @param uriInfo the request uriInfo. 556 * @param path path for the POST request. 557 * @param op POST operation, default is @link org.apache.hadoop.fs.http.client.HttpFSFileSystem.PostOpValues#APPEND}. 558 * @param hasData indicates if the append request is uploading data or not (just getting the handle). 559 * @param doAs user being impersonated, defualt value is none. It can be used 560 * only if the current user is a HttpFSServer proxyuser. 561 * 562 * @return the request response. 563 * 564 * @throws IOException thrown if an IO error occurred. Thrown exceptions are 565 * handled by {@link HttpFSExceptionProvider}. 566 * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown 567 * exceptions are handled by {@link HttpFSExceptionProvider}. 568 */ 569 @POST 570 @Path("{path:.*}") 571 @Consumes({"*/*"}) 572 @Produces({MediaType.APPLICATION_JSON}) 573 public Response post(InputStream is, 574 @Context Principal user, 575 @Context UriInfo uriInfo, 576 @PathParam("path") FsPathParam path, 577 @QueryParam(PostOpParam.NAME) PostOpParam op, 578 @QueryParam(DataParam.NAME) @DefaultValue(DataParam.DEFAULT) DataParam hasData, 579 @QueryParam(DoAsParam.NAME) @DefaultValue(DoAsParam.DEFAULT) DoAsParam doAs) 580 throws IOException, FileSystemAccessException { 581 Response response = null; 582 if (op == null) { 583 throw new UnsupportedOperationException(MessageFormat.format("Missing [{0}] parameter", PostOpParam.NAME)); 584 } 585 path.makeAbsolute(); 586 MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name()); 587 switch (op.value()) { 588 case APPEND: { 589 if (!hasData.value()) { 590 response = Response.temporaryRedirect( 591 createUploadRedirectionURL(uriInfo, HttpFSFileSystem.PostOpValues.APPEND)).build(); 592 } else { 593 FSOperations.FSAppend command = new FSOperations.FSAppend(is, path.value()); 594 fsExecute(user, doAs.value(), command); 595 AUDIT_LOG.info("[{}]", path); 596 response = Response.ok().type(MediaType.APPLICATION_JSON).build(); 597 } 598 break; 599 } 600 } 601 return response; 602 } 603 604 }