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.classification.InterfaceAudience;
022    import org.apache.hadoop.conf.Configuration;
023    import org.apache.hadoop.fs.FileSystem;
024    import org.apache.hadoop.fs.XAttrCodec;
025    import org.apache.hadoop.fs.XAttrSetFlag;
026    import org.apache.hadoop.fs.http.client.HttpFSFileSystem;
027    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.AccessTimeParam;
028    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.AclPermissionParam;
029    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.BlockSizeParam;
030    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.DataParam;
031    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.DestinationParam;
032    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.FilterParam;
033    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.GroupParam;
034    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.LenParam;
035    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.ModifiedTimeParam;
036    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.OffsetParam;
037    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.OperationParam;
038    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.OverwriteParam;
039    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.OwnerParam;
040    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.PermissionParam;
041    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.RecursiveParam;
042    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.ReplicationParam;
043    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.SourcesParam;
044    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.XAttrEncodingParam;
045    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.XAttrNameParam;
046    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.XAttrSetFlagParam;
047    import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.XAttrValueParam;
048    import org.apache.hadoop.lib.service.FileSystemAccess;
049    import org.apache.hadoop.lib.service.FileSystemAccessException;
050    import org.apache.hadoop.lib.service.Groups;
051    import org.apache.hadoop.lib.service.Instrumentation;
052    import org.apache.hadoop.lib.servlet.FileSystemReleaseFilter;
053    import org.apache.hadoop.lib.wsrs.InputStreamEntity;
054    import org.apache.hadoop.lib.wsrs.Parameters;
055    import org.apache.hadoop.security.UserGroupInformation;
056    import org.apache.hadoop.security.token.delegation.web.HttpUserGroupInformation;
057    import org.json.simple.JSONObject;
058    import org.slf4j.Logger;
059    import org.slf4j.LoggerFactory;
060    import org.slf4j.MDC;
061    
062    import javax.ws.rs.Consumes;
063    import javax.ws.rs.DELETE;
064    import javax.ws.rs.GET;
065    import javax.ws.rs.POST;
066    import javax.ws.rs.PUT;
067    import javax.ws.rs.Path;
068    import javax.ws.rs.PathParam;
069    import javax.ws.rs.Produces;
070    import javax.ws.rs.QueryParam;
071    import javax.ws.rs.core.Context;
072    import javax.ws.rs.core.MediaType;
073    import javax.ws.rs.core.Response;
074    import javax.ws.rs.core.UriBuilder;
075    import javax.ws.rs.core.UriInfo;
076    import java.io.IOException;
077    import java.io.InputStream;
078    import java.net.URI;
079    import java.security.AccessControlException;
080    import java.text.MessageFormat;
081    import java.util.EnumSet;
082    import java.util.List;
083    import java.util.Map;
084    
085    /**
086     * Main class of HttpFSServer server.
087     * <p/>
088     * The <code>HttpFSServer</code> class uses Jersey JAX-RS to binds HTTP requests to the
089     * different operations.
090     */
091    @Path(HttpFSFileSystem.SERVICE_VERSION)
092    @InterfaceAudience.Private
093    public class HttpFSServer {
094      private static Logger AUDIT_LOG = LoggerFactory.getLogger("httpfsaudit");
095    
096      /**
097       * Executes a {@link FileSystemAccess.FileSystemExecutor} using a filesystem for the effective
098       * user.
099       *
100       * @param ugi user making the request.
101       * @param executor FileSystemExecutor to execute.
102       *
103       * @return FileSystemExecutor response
104       *
105       * @throws IOException thrown if an IO error occurrs.
106       * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown
107       * exceptions are handled by {@link HttpFSExceptionProvider}.
108       */
109      private <T> T fsExecute(UserGroupInformation ugi, FileSystemAccess.FileSystemExecutor<T> executor)
110        throws IOException, FileSystemAccessException {
111        FileSystemAccess fsAccess = HttpFSServerWebApp.get().get(FileSystemAccess.class);
112        Configuration conf = HttpFSServerWebApp.get().get(FileSystemAccess.class).getFileSystemConfiguration();
113        return fsAccess.execute(ugi.getShortUserName(), conf, executor);
114      }
115    
116      /**
117       * Returns a filesystem instance. The fileystem instance is wired for release at the completion of
118       * the current Servlet request via the {@link FileSystemReleaseFilter}.
119       * <p/>
120       * If a do-as user is specified, the current user must be a valid proxyuser, otherwise an
121       * <code>AccessControlException</code> will be thrown.
122       *
123       * @param ugi principal for whom the filesystem instance is.
124       *
125       * @return a filesystem for the specified user or do-as user.
126       *
127       * @throws IOException thrown if an IO error occurred. Thrown exceptions are
128       * handled by {@link HttpFSExceptionProvider}.
129       * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown
130       * exceptions are handled by {@link HttpFSExceptionProvider}.
131       */
132      private FileSystem createFileSystem(UserGroupInformation ugi)
133          throws IOException, FileSystemAccessException {
134        String hadoopUser = ugi.getShortUserName();
135        FileSystemAccess fsAccess = HttpFSServerWebApp.get().get(FileSystemAccess.class);
136        Configuration conf = HttpFSServerWebApp.get().get(FileSystemAccess.class).getFileSystemConfiguration();
137        FileSystem fs = fsAccess.createFileSystem(hadoopUser, conf);
138        FileSystemReleaseFilter.setFileSystem(fs);
139        return fs;
140      }
141    
142      private void enforceRootPath(HttpFSFileSystem.Operation op, String path) {
143        if (!path.equals("/")) {
144          throw new UnsupportedOperationException(
145            MessageFormat.format("Operation [{0}], invalid path [{1}], must be '/'",
146                                 op, path));
147        }
148      }
149    
150      /**
151       * Special binding for '/' as it is not handled by the wildcard binding.
152       *
153       * @param op the HttpFS operation of the request.
154       * @param params the HttpFS parameters of the request.
155       *
156       * @return the request response.
157       *
158       * @throws IOException thrown if an IO error occurred. Thrown exceptions are
159       * handled by {@link HttpFSExceptionProvider}.
160       * @throws FileSystemAccessException thrown if a FileSystemAccess releated
161       * error occurred. Thrown exceptions are handled by
162       * {@link HttpFSExceptionProvider}.
163       */
164      @GET
165      @Produces(MediaType.APPLICATION_JSON)
166      public Response getRoot(@QueryParam(OperationParam.NAME) OperationParam op,
167                              @Context Parameters params)
168        throws IOException, FileSystemAccessException {
169        return get("", op, params);
170      }
171    
172      private String makeAbsolute(String path) {
173        return "/" + ((path != null) ? path : "");
174      }
175    
176      /**
177       * Binding to handle GET requests, supported operations are
178       *
179       * @param path the path for operation.
180       * @param op the HttpFS operation of the request.
181       * @param params the HttpFS parameters of the request.
182       *
183       * @return the request response.
184       *
185       * @throws IOException thrown if an IO error occurred. Thrown exceptions are
186       * handled by {@link HttpFSExceptionProvider}.
187       * @throws FileSystemAccessException thrown if a FileSystemAccess releated
188       * error occurred. Thrown exceptions are handled by
189       * {@link HttpFSExceptionProvider}.
190       */
191      @GET
192      @Path("{path:.*}")
193      @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON})
194      public Response get(@PathParam("path") String path,
195                          @QueryParam(OperationParam.NAME) OperationParam op,
196                          @Context Parameters params)
197        throws IOException, FileSystemAccessException {
198        UserGroupInformation user = HttpUserGroupInformation.get();
199        Response response;
200        path = makeAbsolute(path);
201        MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name());
202        switch (op.value()) {
203          case OPEN: {
204            //Invoking the command directly using an unmanaged FileSystem that is
205            // released by the FileSystemReleaseFilter
206            FSOperations.FSOpen command = new FSOperations.FSOpen(path);
207            FileSystem fs = createFileSystem(user);
208            InputStream is = command.execute(fs);
209            Long offset = params.get(OffsetParam.NAME, OffsetParam.class);
210            Long len = params.get(LenParam.NAME, LenParam.class);
211            AUDIT_LOG.info("[{}] offset [{}] len [{}]",
212                           new Object[]{path, offset, len});
213            InputStreamEntity entity = new InputStreamEntity(is, offset, len);
214            response =
215              Response.ok(entity).type(MediaType.APPLICATION_OCTET_STREAM).build();
216            break;
217          }
218          case GETFILESTATUS: {
219            FSOperations.FSFileStatus command =
220              new FSOperations.FSFileStatus(path);
221            Map json = fsExecute(user, command);
222            AUDIT_LOG.info("[{}]", path);
223            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
224            break;
225          }
226          case LISTSTATUS: {
227            String filter = params.get(FilterParam.NAME, FilterParam.class);
228            FSOperations.FSListStatus command = new FSOperations.FSListStatus(
229              path, filter);
230            Map json = fsExecute(user, command);
231            AUDIT_LOG.info("[{}] filter [{}]", path,
232                           (filter != null) ? filter : "-");
233            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
234            break;
235          }
236          case GETHOMEDIRECTORY: {
237            enforceRootPath(op.value(), path);
238            FSOperations.FSHomeDir command = new FSOperations.FSHomeDir();
239            JSONObject json = fsExecute(user, command);
240            AUDIT_LOG.info("");
241            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
242            break;
243          }
244          case INSTRUMENTATION: {
245            enforceRootPath(op.value(), path);
246            Groups groups = HttpFSServerWebApp.get().get(Groups.class);
247            List<String> userGroups = groups.getGroups(user.getShortUserName());
248            if (!userGroups.contains(HttpFSServerWebApp.get().getAdminGroup())) {
249              throw new AccessControlException(
250                "User not in HttpFSServer admin group");
251            }
252            Instrumentation instrumentation =
253              HttpFSServerWebApp.get().get(Instrumentation.class);
254            Map snapshot = instrumentation.getSnapshot();
255            response = Response.ok(snapshot).build();
256            break;
257          }
258          case GETCONTENTSUMMARY: {
259            FSOperations.FSContentSummary command =
260              new FSOperations.FSContentSummary(path);
261            Map json = fsExecute(user, command);
262            AUDIT_LOG.info("[{}]", path);
263            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
264            break;
265          }
266          case GETFILECHECKSUM: {
267            FSOperations.FSFileChecksum command =
268              new FSOperations.FSFileChecksum(path);
269            Map json = fsExecute(user, command);
270            AUDIT_LOG.info("[{}]", path);
271            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
272            break;
273          }
274          case GETFILEBLOCKLOCATIONS: {
275            response = Response.status(Response.Status.BAD_REQUEST).build();
276            break;
277          }
278          case GETACLSTATUS: {
279            FSOperations.FSAclStatus command =
280                    new FSOperations.FSAclStatus(path);
281            Map json = fsExecute(user, command);
282            AUDIT_LOG.info("ACL status for [{}]", path);
283            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
284            break;
285          }
286          case GETXATTRS: {
287            List<String> xattrNames = params.getValues(XAttrNameParam.NAME, 
288                XAttrNameParam.class);
289            XAttrCodec encoding = params.get(XAttrEncodingParam.NAME, 
290                XAttrEncodingParam.class);
291            FSOperations.FSGetXAttrs command = new FSOperations.FSGetXAttrs(path, 
292                xattrNames, encoding);
293            @SuppressWarnings("rawtypes")
294            Map json = fsExecute(user, command);
295            AUDIT_LOG.info("XAttrs for [{}]", path);
296            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
297            break;
298          }
299          case LISTXATTRS: {
300            FSOperations.FSListXAttrs command = new FSOperations.FSListXAttrs(path);
301            @SuppressWarnings("rawtypes")
302            Map json = fsExecute(user, command);
303            AUDIT_LOG.info("XAttr names for [{}]", path);
304            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
305            break;
306          }
307          default: {
308            throw new IOException(
309              MessageFormat.format("Invalid HTTP GET operation [{0}]",
310                                   op.value()));
311          }
312        }
313        return response;
314      }
315    
316    
317      /**
318       * Binding to handle DELETE requests.
319       *
320       * @param path the path for operation.
321       * @param op the HttpFS operation of the request.
322       * @param params the HttpFS parameters of the request.
323       *
324       * @return the request response.
325       *
326       * @throws IOException thrown if an IO error occurred. Thrown exceptions are
327       * handled by {@link HttpFSExceptionProvider}.
328       * @throws FileSystemAccessException thrown if a FileSystemAccess releated
329       * error occurred. Thrown exceptions are handled by
330       * {@link HttpFSExceptionProvider}.
331       */
332      @DELETE
333      @Path("{path:.*}")
334      @Produces(MediaType.APPLICATION_JSON)
335      public Response delete(@PathParam("path") String path,
336                             @QueryParam(OperationParam.NAME) OperationParam op,
337                             @Context Parameters params)
338        throws IOException, FileSystemAccessException {
339        UserGroupInformation user = HttpUserGroupInformation.get();
340        Response response;
341        path = makeAbsolute(path);
342        MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name());
343        switch (op.value()) {
344          case DELETE: {
345            Boolean recursive =
346              params.get(RecursiveParam.NAME,  RecursiveParam.class);
347            AUDIT_LOG.info("[{}] recursive [{}]", path, recursive);
348            FSOperations.FSDelete command =
349              new FSOperations.FSDelete(path, recursive);
350            JSONObject json = fsExecute(user, command);
351            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
352            break;
353          }
354          default: {
355            throw new IOException(
356              MessageFormat.format("Invalid HTTP DELETE operation [{0}]",
357                                   op.value()));
358          }
359        }
360        return response;
361      }
362    
363      /**
364       * Binding to handle POST requests.
365       *
366       * @param is the inputstream for the request payload.
367       * @param uriInfo the of the request.
368       * @param path the path for operation.
369       * @param op the HttpFS operation of the request.
370       * @param params the HttpFS parameters of the request.
371       *
372       * @return the request response.
373       *
374       * @throws IOException thrown if an IO error occurred. Thrown exceptions are
375       * handled by {@link HttpFSExceptionProvider}.
376       * @throws FileSystemAccessException thrown if a FileSystemAccess releated
377       * error occurred. Thrown exceptions are handled by
378       * {@link HttpFSExceptionProvider}.
379       */
380      @POST
381      @Path("{path:.*}")
382      @Consumes({"*/*"})
383      @Produces({MediaType.APPLICATION_JSON})
384      public Response post(InputStream is,
385                           @Context UriInfo uriInfo,
386                           @PathParam("path") String path,
387                           @QueryParam(OperationParam.NAME) OperationParam op,
388                           @Context Parameters params)
389        throws IOException, FileSystemAccessException {
390        UserGroupInformation user = HttpUserGroupInformation.get();
391        Response response;
392        path = makeAbsolute(path);
393        MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name());
394        switch (op.value()) {
395          case APPEND: {
396            Boolean hasData = params.get(DataParam.NAME, DataParam.class);
397            if (!hasData) {
398              response = Response.temporaryRedirect(
399                createUploadRedirectionURL(uriInfo,
400                  HttpFSFileSystem.Operation.APPEND)).build();
401            } else {
402              FSOperations.FSAppend command =
403                new FSOperations.FSAppend(is, path);
404              fsExecute(user, command);
405              AUDIT_LOG.info("[{}]", path);
406              response = Response.ok().type(MediaType.APPLICATION_JSON).build();
407            }
408            break;
409          }
410          case CONCAT: {
411            System.out.println("HTTPFS SERVER CONCAT");
412            String sources = params.get(SourcesParam.NAME, SourcesParam.class);
413    
414            FSOperations.FSConcat command =
415                new FSOperations.FSConcat(path, sources.split(","));
416            fsExecute(user, command);
417            AUDIT_LOG.info("[{}]", path);
418            System.out.println("SENT RESPONSE");
419            response = Response.ok().build();
420            break;
421          }
422          default: {
423            throw new IOException(
424              MessageFormat.format("Invalid HTTP POST operation [{0}]",
425                                   op.value()));
426          }
427        }
428        return response;
429      }
430    
431      /**
432       * Creates the URL for an upload operation (create or append).
433       *
434       * @param uriInfo uri info of the request.
435       * @param uploadOperation operation for the upload URL.
436       *
437       * @return the URI for uploading data.
438       */
439      protected URI createUploadRedirectionURL(UriInfo uriInfo, Enum<?> uploadOperation) {
440        UriBuilder uriBuilder = uriInfo.getRequestUriBuilder();
441        uriBuilder = uriBuilder.replaceQueryParam(OperationParam.NAME, uploadOperation).
442          queryParam(DataParam.NAME, Boolean.TRUE);
443        return uriBuilder.build(null);
444      }
445    
446    
447      /**
448       * Binding to handle PUT requests.
449       *
450       * @param is the inputstream for the request payload.
451       * @param uriInfo the of the request.
452       * @param path the path for operation.
453       * @param op the HttpFS operation of the request.
454       * @param params the HttpFS parameters of the request.
455       *
456       * @return the request response.
457       *
458       * @throws IOException thrown if an IO error occurred. Thrown exceptions are
459       * handled by {@link HttpFSExceptionProvider}.
460       * @throws FileSystemAccessException thrown if a FileSystemAccess releated
461       * error occurred. Thrown exceptions are handled by
462       * {@link HttpFSExceptionProvider}.
463       */
464      @PUT
465      @Path("{path:.*}")
466      @Consumes({"*/*"})
467      @Produces({MediaType.APPLICATION_JSON})
468      public Response put(InputStream is,
469                           @Context UriInfo uriInfo,
470                           @PathParam("path") String path,
471                           @QueryParam(OperationParam.NAME) OperationParam op,
472                           @Context Parameters params)
473        throws IOException, FileSystemAccessException {
474        UserGroupInformation user = HttpUserGroupInformation.get();
475        Response response;
476        path = makeAbsolute(path);
477        MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name());
478        switch (op.value()) {
479          case CREATE: {
480            Boolean hasData = params.get(DataParam.NAME, DataParam.class);
481            if (!hasData) {
482              response = Response.temporaryRedirect(
483                createUploadRedirectionURL(uriInfo,
484                  HttpFSFileSystem.Operation.CREATE)).build();
485            } else {
486              Short permission = params.get(PermissionParam.NAME,
487                                             PermissionParam.class);
488              Boolean override = params.get(OverwriteParam.NAME,
489                                            OverwriteParam.class);
490              Short replication = params.get(ReplicationParam.NAME,
491                                             ReplicationParam.class);
492              Long blockSize = params.get(BlockSizeParam.NAME,
493                                          BlockSizeParam.class);
494              FSOperations.FSCreate command =
495                new FSOperations.FSCreate(is, path, permission, override,
496                                          replication, blockSize);
497              fsExecute(user, command);
498              AUDIT_LOG.info(
499                "[{}] permission [{}] override [{}] replication [{}] blockSize [{}]",
500                new Object[]{path, permission, override, replication, blockSize});
501              response = Response.status(Response.Status.CREATED).build();
502            }
503            break;
504          }
505          case SETXATTR: {
506            String xattrName = params.get(XAttrNameParam.NAME, 
507                XAttrNameParam.class);
508            String xattrValue = params.get(XAttrValueParam.NAME, 
509                XAttrValueParam.class);
510            EnumSet<XAttrSetFlag> flag = params.get(XAttrSetFlagParam.NAME, 
511                XAttrSetFlagParam.class);
512    
513            FSOperations.FSSetXAttr command = new FSOperations.FSSetXAttr(
514                path, xattrName, xattrValue, flag);
515            fsExecute(user, command);
516            AUDIT_LOG.info("[{}] to xAttr [{}]", path, xattrName);
517            response = Response.ok().build();
518            break;
519          }
520          case REMOVEXATTR: {
521            String xattrName = params.get(XAttrNameParam.NAME, XAttrNameParam.class);
522            FSOperations.FSRemoveXAttr command = new FSOperations.FSRemoveXAttr(
523                path, xattrName);
524            fsExecute(user, command);
525            AUDIT_LOG.info("[{}] removed xAttr [{}]", path, xattrName);
526            response = Response.ok().build();
527            break;
528          }
529          case MKDIRS: {
530            Short permission = params.get(PermissionParam.NAME,
531                                           PermissionParam.class);
532            FSOperations.FSMkdirs command =
533              new FSOperations.FSMkdirs(path, permission);
534            JSONObject json = fsExecute(user, command);
535            AUDIT_LOG.info("[{}] permission [{}]", path, permission);
536            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
537            break;
538          }
539          case RENAME: {
540            String toPath = params.get(DestinationParam.NAME, DestinationParam.class);
541            FSOperations.FSRename command =
542              new FSOperations.FSRename(path, toPath);
543            JSONObject json = fsExecute(user, command);
544            AUDIT_LOG.info("[{}] to [{}]", path, toPath);
545            response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
546            break;
547          }
548          case SETOWNER: {
549            String owner = params.get(OwnerParam.NAME, OwnerParam.class);
550            String group = params.get(GroupParam.NAME, GroupParam.class);
551            FSOperations.FSSetOwner command =
552              new FSOperations.FSSetOwner(path, owner, group);
553            fsExecute(user, command);
554            AUDIT_LOG.info("[{}] to (O/G)[{}]", path, owner + ":" + group);
555            response = Response.ok().build();
556            break;
557          }
558          case SETPERMISSION: {
559            Short permission = params.get(PermissionParam.NAME,
560                                          PermissionParam.class);
561            FSOperations.FSSetPermission command =
562              new FSOperations.FSSetPermission(path, permission);
563            fsExecute(user, command);
564            AUDIT_LOG.info("[{}] to [{}]", path, permission);
565            response = Response.ok().build();
566            break;
567          }
568          case SETREPLICATION: {
569            Short replication = params.get(ReplicationParam.NAME,
570                                           ReplicationParam.class);
571            FSOperations.FSSetReplication command =
572              new FSOperations.FSSetReplication(path, replication);
573            JSONObject json = fsExecute(user, command);
574            AUDIT_LOG.info("[{}] to [{}]", path, replication);
575            response = Response.ok(json).build();
576            break;
577          }
578          case SETTIMES: {
579            Long modifiedTime = params.get(ModifiedTimeParam.NAME,
580                                           ModifiedTimeParam.class);
581            Long accessTime = params.get(AccessTimeParam.NAME,
582                                         AccessTimeParam.class);
583            FSOperations.FSSetTimes command =
584              new FSOperations.FSSetTimes(path, modifiedTime, accessTime);
585            fsExecute(user, command);
586            AUDIT_LOG.info("[{}] to (M/A)[{}]", path,
587                           modifiedTime + ":" + accessTime);
588            response = Response.ok().build();
589            break;
590          }
591          case SETACL: {
592            String aclSpec = params.get(AclPermissionParam.NAME,
593                    AclPermissionParam.class);
594            FSOperations.FSSetAcl command =
595                    new FSOperations.FSSetAcl(path, aclSpec);
596            fsExecute(user, command);
597            AUDIT_LOG.info("[{}] to acl [{}]", path, aclSpec);
598            response = Response.ok().build();
599            break;
600          }
601          case REMOVEACL: {
602            FSOperations.FSRemoveAcl command =
603                    new FSOperations.FSRemoveAcl(path);
604            fsExecute(user, command);
605            AUDIT_LOG.info("[{}] removed acl", path);
606            response = Response.ok().build();
607            break;
608          }
609          case MODIFYACLENTRIES: {
610            String aclSpec = params.get(AclPermissionParam.NAME,
611                    AclPermissionParam.class);
612            FSOperations.FSModifyAclEntries command =
613                    new FSOperations.FSModifyAclEntries(path, aclSpec);
614            fsExecute(user, command);
615            AUDIT_LOG.info("[{}] modify acl entry with [{}]", path, aclSpec);
616            response = Response.ok().build();
617            break;
618          }
619          case REMOVEACLENTRIES: {
620            String aclSpec = params.get(AclPermissionParam.NAME,
621                    AclPermissionParam.class);
622            FSOperations.FSRemoveAclEntries command =
623                    new FSOperations.FSRemoveAclEntries(path, aclSpec);
624            fsExecute(user, command);
625            AUDIT_LOG.info("[{}] remove acl entry [{}]", path, aclSpec);
626            response = Response.ok().build();
627            break;
628          }
629          case REMOVEDEFAULTACL: {
630            FSOperations.FSRemoveDefaultAcl command =
631                    new FSOperations.FSRemoveDefaultAcl(path);
632            fsExecute(user, command);
633            AUDIT_LOG.info("[{}] remove default acl", path);
634            response = Response.ok().build();
635            break;
636          }
637          default: {
638            throw new IOException(
639              MessageFormat.format("Invalid HTTP PUT operation [{0}]",
640                                   op.value()));
641          }
642        }
643        return response;
644      }
645    
646    }