Package org.eclipse.orion.internal.server.servlets.file

Source Code of org.eclipse.orion.internal.server.servlets.file.FileHandlerV1

/*******************************************************************************
* Copyright (c) 2010, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.orion.internal.server.servlets.file;

import java.io.*;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.provider.FileInfo;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.orion.internal.server.servlets.ServletResourceHandler;
import org.eclipse.orion.server.core.IOUtilities;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.ServerStatus;
import org.eclipse.orion.server.core.resources.UniversalUniqueIdentifier;
import org.eclipse.orion.server.servlets.JsonURIUnqualificationStrategy;
import org.eclipse.orion.server.servlets.OrionServlet;
import org.eclipse.osgi.util.NLS;
import org.json.*;

/**
* Handles files in version 1 of eclipse web protocol syntax.
*/
class FileHandlerV1 extends GenericFileHandler {
  final ServletResourceHandler<IStatus> statusHandler;

  FileHandlerV1(ServletResourceHandler<IStatus> statusHandler, ServletContext context) {
    super(context);
    this.statusHandler = statusHandler;
  }

  /**
   * The end of line sequence expected by HTTP.
   */
  private static final String EOL = "\r\n"; //$NON-NLS-1$

  /**
   * Appends metadata to a Writer. Does not flush the Writer.
   */
  protected void appendGetMetadata(HttpServletRequest request, HttpServletResponse response, Writer responseWriter, IFileStore file) throws IOException, NoSuchAlgorithmException, JSONException, CoreException {
    JSONObject metadata = getMetadata(request, file);
    response.setHeader(ProtocolConstants.KEY_ETAG, metadata.getString(ProtocolConstants.KEY_ETAG));
    response.setHeader("Cache-Control", "no-cache"); //$NON-NLS-1$ //$NON-NLS-2$
    OrionServlet.decorateResponse(request, metadata, JsonURIUnqualificationStrategy.ALL);
    responseWriter.append(metadata.toString());
  }

  /**
   * Writes metadata to the response.
   */
  protected void handleGetMetadata(HttpServletRequest request, HttpServletResponse response, IFileStore file) throws IOException, NoSuchAlgorithmException, JSONException, CoreException {
    JSONObject metadata = getMetadata(request, file);
    response.setHeader(ProtocolConstants.KEY_ETAG, metadata.getString(ProtocolConstants.KEY_ETAG));
    OrionServlet.writeJSONResponse(request, response, metadata);
  }

  /**
   * @return Metadata for the file. The returned object is guaranteed to have an ETag string.
   */
  private JSONObject getMetadata(HttpServletRequest request, IFileStore file) throws CoreException, NoSuchAlgorithmException, IOException, JSONException {
    JSONObject metadata = ServletFileStoreHandler.toJSON(file, file.fetchInfo(EFS.NONE, null), getURI(request));
    metadata.put(ProtocolConstants.KEY_ETAG, generateFileETag(file));
    return metadata;
  }

  private void handleMultiPartGet(HttpServletRequest request, HttpServletResponse response, IFileStore file) throws IOException, CoreException, NoSuchAlgorithmException, JSONException {
    String boundary = createBoundaryString();
    response.setHeader(ProtocolConstants.HEADER_ACCEPT_PATCH, ProtocolConstants.CONTENT_TYPE_JSON_PATCH);
    response.setHeader(ProtocolConstants.HEADER_CONTENT_TYPE, "multipart/related; boundary=\"" + boundary + '"'); //$NON-NLS-1$
    OutputStream outputStream = response.getOutputStream();
    Writer out = new OutputStreamWriter(outputStream, "UTF-8");
    out.write("--" + boundary + EOL); //$NON-NLS-1$
    out.write("Content-Type: application/json" + EOL + EOL); //$NON-NLS-1$
    appendGetMetadata(request, response, out, file);
    out.write(EOL + "--" + boundary + EOL); //$NON-NLS-1$
    // headers for file contents go here
    out.write(EOL);
    out.flush();
    IOUtilities.pipe(file.openInputStream(EFS.NONE, null), outputStream, true, false);
    out.write(EOL + "--" + boundary + EOL); //$NON-NLS-1$
    out.flush();
  }

  String createBoundaryString() {
    return new UniversalUniqueIdentifier().toBase64String();
  }

  private void handlePutContents(HttpServletRequest request, ServletInputStream requestStream, HttpServletResponse response, IFileStore file) throws IOException, CoreException, NoSuchAlgorithmException, JSONException {
    String source = request.getParameter(ProtocolConstants.PARM_SOURCE);
    if (source != null) {
      //if source is specified, read contents from different URL rather than from this request stream
      IOUtilities.pipe(new URL(source).openStream(), file.openOutputStream(EFS.NONE, null), true, true);
    } else {
      //read from the request stream
      IOUtilities.pipe(requestStream, file.openOutputStream(EFS.NONE, null), false, true);
    }

    // return metadata with the new Etag
    handleGetMetadata(request, response, file);
  }

  private void handlePatchContents(HttpServletRequest request, BufferedReader requestReader, HttpServletResponse response, IFileStore file) throws IOException, CoreException, NoSuchAlgorithmException, JSONException, ServletException {
    JSONObject changes = OrionServlet.readJSONRequest(request);
    //read file to memory
    Reader fileReader = new InputStreamReader(file.openInputStream(EFS.NONE, null));
    StringWriter oldFile = new StringWriter();
    IOUtilities.pipe(fileReader, oldFile, true, false);
    StringBuffer oldContents = oldFile.getBuffer();

    JSONArray changeList = changes.getJSONArray("diff");
    for (int i = 0; i < changeList.length(); i++) {
      JSONObject change = changeList.getJSONObject(i);
      long start = change.getLong("start");
      long end = change.getLong("end");
      String text = change.getString("text");
      oldContents.replace((int) start, (int) end, text);
    }

    String newContents = oldContents.toString();
    boolean failed = false;
    if (changes.has("contents")) {
      String contents = changes.getString("contents");
      if (!newContents.equals(contents)) {
        failed = true;
        newContents = contents;
      }
    }
    Writer fileWriter = new OutputStreamWriter(file.openOutputStream(EFS.NONE, null), "UTF-8");
    IOUtilities.pipe(new StringReader(newContents), fileWriter, false, true);
    if (failed) {
      statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_ACCEPTABLE, "Bad File Diffs. Please paste this content in a bug report: \u00A0\u00A0   " + changes.toString(), null));
      return;
    }

    // return metadata with the new Etag
    handleGetMetadata(request, response, file);
  }

  private void handleMultiPartPut(HttpServletRequest request, HttpServletResponse response, IFileStore file) throws IOException, CoreException, JSONException, NoSuchAlgorithmException {
    String typeHeader = request.getHeader(ProtocolConstants.HEADER_CONTENT_TYPE);
    String boundary = typeHeader.substring(typeHeader.indexOf("boundary=\"") + 10, typeHeader.length() - 1); //$NON-NLS-1$
    ServletInputStream requestStream = request.getInputStream();
    BufferedReader requestReader = new BufferedReader(new InputStreamReader(requestStream, "UTF-8")); //$NON-NLS-1$
    handlePutMetadata(requestReader, boundary, file);
    // next come the headers for the content
    Map<String, String> contentHeaders = new HashMap<String, String>();
    String line;
    while ((line = requestReader.readLine()) != null && line.length() > 0) {
      String[] header = line.split(":"); //$NON-NLS-1$
      if (header.length == 2)
        contentHeaders.put(header[0], header[1]);
    }
    // now for the file contents
    handlePutContents(request, requestStream, response, file);
  }

  private void handlePutMetadata(BufferedReader reader, String boundary, IFileStore file) throws IOException, CoreException, JSONException {
    StringBuffer buf = new StringBuffer();
    String line;
    while ((line = reader.readLine()) != null && !line.equals(boundary))
      buf.append(line);
    //merge with existing metadata
    FileInfo info = (FileInfo) file.fetchInfo(EFS.NONE, null);
    ServletFileStoreHandler.copyJSONToFileInfo(new JSONObject(buf.toString()), info);
    file.putInfo(info, EFS.SET_ATTRIBUTES, null);
  }

  @Override
  public boolean handleRequest(HttpServletRequest request, HttpServletResponse response, IFileStore file) throws ServletException {
    try {
      String fileETag = generateFileETag(file);
      if (handleIfMatchHeader(request, response, fileETag)) {
        return true;
      }
      if (handleIfNoneMatchHeader(request, response, fileETag)) {
        return true;
      }

      String parts = IOUtilities.getQueryParameter(request, "parts");
      if (parts == null || "body".equals(parts)) { //$NON-NLS-1$
        switch (getMethod(request)) {
          case DELETE :
            file.delete(EFS.NONE, null);
            break;
          case PUT :
            handlePutContents(request, request.getInputStream(), response, file);
            break;
          case POST :
            if ("PATCH".equals(request.getHeader(ProtocolConstants.HEADER_METHOD_OVERRIDE))) {
              handlePatchContents(request, request.getReader(), response, file);
            }
            break;
          default :
            return handleFileContents(request, response, file);
        }
        return true;
      }
      if ("meta".equals(parts)) { //$NON-NLS-1$
        switch (getMethod(request)) {
          case GET :
            handleGetMetadata(request, response, file);
            return true;
          case PUT :
            handlePutMetadata(request.getReader(), null, file);
            response.setStatus(HttpServletResponse.SC_NO_CONTENT);
            return true;
          default :
            return false;
        }
      }
      if ("meta,body".equals(parts) || "body,meta".equals(parts)) { //$NON-NLS-1$ //$NON-NLS-2$
        switch (getMethod(request)) {
          case GET :
            handleMultiPartGet(request, response, file);
            return true;
          case PUT :
            handleMultiPartPut(request, response, file);
            return true;
          default :
            return false;
        }
      }
    } catch (JSONException e) {
      return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Syntax error in request", e));
    } catch (Exception e) {
      if (!handleAuthFailure(request, response, e))
        throw new ServletException(NLS.bind("Error retrieving file: {0}", file), e);
    }
    return false;
  }
}
TOP

Related Classes of org.eclipse.orion.internal.server.servlets.file.FileHandlerV1

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.