/*******************************************************************************
* Copyright (c) 2011, 2014 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.xfer;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.orion.internal.server.servlets.Slug;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.resources.UniversalUniqueIdentifier;
import org.eclipse.orion.server.servlets.OrionServlet;
/**
* A servlet for doing imports and exports of large files.
*/
public class TransferServlet extends OrionServlet {
/**
* The servlet path prefix for export operations.
*/
static final String PREFIX_EXPORT = "export";//$NON-NLS-1$
/**
* The servlet path prefix for import operations.
*/
static final String PREFIX_IMPORT = "import";//$NON-NLS-1$
private static final long serialVersionUID = 1L;
public TransferServlet() {
super();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
traceRequest(req);
String pathInfo = req.getPathInfo();
IPath path = pathInfo == null ? Path.ROOT : new Path(pathInfo);
//first segment must be either "import" or "export"
if (path.segmentCount() > 0) {
if (PREFIX_IMPORT.equals(path.segment(0))) {
doPostImport(req, resp);
return;
} else if (PREFIX_EXPORT.equals(path.segment(0))) {
doPostExport(req, resp);
return;
}
}
//we don't know how to interpret this request
super.doPost(req, resp);
}
private void doPostExport(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String optionString = req.getHeader(ProtocolConstants.HEADER_XFER_OPTIONS);
List<String> options = getOptions(optionString);
if (options.contains("sftp")) { //$NON-NLS-1$
new SFTPTransfer(req, resp, getStatusHandler(), options).doTransfer();
return;
}
//don't know how to handle this
super.doPost(req, resp);
}
static List<String> getOptions(String optionString) {
if (optionString == null)
optionString = ""; //$NON-NLS-1$
return Arrays.asList(optionString.split(",")); //$NON-NLS-1$
}
protected void doPostImport(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//initiating a new file transfer
String optionString = req.getHeader(ProtocolConstants.HEADER_XFER_OPTIONS);
List<String> options = getOptions(optionString);
if (options.contains("sftp")) { //$NON-NLS-1$
new SFTPTransfer(req, resp, getStatusHandler(), options).doTransfer();
return;
}
String sourceURL = req.getParameter(ProtocolConstants.PARM_SOURCE);
long length = -1;
try {
//length must be provided unless we are importing from another URL
if (sourceURL == null) {
//a chunked upload indicates the length to be uploaded in future calls
String lengthHeader = req.getHeader(ProtocolConstants.HEADER_XFER_LENGTH);
//a regular content length indicates the file to be uploaded is included in the post
if (lengthHeader == null)
lengthHeader = req.getHeader(ProtocolConstants.HEADER_CONTENT_LENGTH);
length = Long.parseLong(lengthHeader);
}
} catch (NumberFormatException e) {
handleException(resp, "Transfer request must indicate transfer size", e, HttpServletResponse.SC_BAD_REQUEST);
return;
}
boolean unzip = !options.contains("raw"); //$NON-NLS-1$
String slugHeader = req.getHeader(ProtocolConstants.HEADER_SLUG);
String fileName = Slug.decode(slugHeader);
//if file name is not provided we can guess from the source URL
if (fileName == null && sourceURL != null) {
int lastSlash = sourceURL.lastIndexOf('/');
if (lastSlash > 0)
fileName = sourceURL.substring(lastSlash + 1);
}
if (fileName == null && !unzip) {
handleException(resp, "Transfer request must indicate target filename", null, HttpServletResponse.SC_BAD_REQUEST);
return;
}
//chop "import" segment off the front
IPath path = new Path(req.getPathInfo()).removeFirstSegments(1);
String uuid = new UniversalUniqueIdentifier().toBase64String();
ClientImport newImport = new ClientImport(uuid, getStatusHandler());
newImport.setPath(path);
newImport.setLength(length);
newImport.setFileName(fileName);
try {
if (sourceURL != null)
newImport.setSourceURL(sourceURL);
} catch (MalformedURLException e) {
handleException(resp, "Invalid input URL", e, HttpServletResponse.SC_BAD_REQUEST);
}
newImport.setOptions(optionString);
newImport.doPost(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
traceRequest(req);
String pathInfo = req.getPathInfo();
IPath path = pathInfo == null ? Path.ROOT : new Path(pathInfo);
if (path.segmentCount() >= 2) {
if (PREFIX_EXPORT.equals(path.segment(0)) && "zip".equals(path.getFileExtension())) { //$NON-NLS-1$
ClientExport export = new ClientExport(path.removeFirstSegments(1).removeFileExtension(), getStatusHandler());
export.doExport(req, resp);
return;
}
}
super.doGet(req, resp);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
traceRequest(req);
String pathInfo = req.getPathInfo();
IPath path = pathInfo == null ? Path.ROOT : new Path(pathInfo);
String id;
//format is /xfer/import/<uuid>
if (path.segmentCount() == 2) {
id = path.segment(1);
ClientImport importOp = new ClientImport(id, getStatusHandler());
importOp.doPut(req, resp);
return;
}
super.doPut(req, resp);
}
}