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