/*******************************************************************************
* Copyright (c) 2015 Zend Technologies 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:
* Zend Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.php.internal.debug.core.zend.debugger.handlers;
import java.io.*;
import java.net.URI;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.php.debug.core.debugger.messages.IDebugMessage;
import org.eclipse.php.debug.core.debugger.messages.IDebugResponseMessage;
import org.eclipse.php.debug.core.debugger.parameters.IDebugParametersKeys;
import org.eclipse.php.internal.debug.core.IPHPDebugConstants;
import org.eclipse.php.internal.debug.core.Logger;
import org.eclipse.php.internal.debug.core.PHPDebugPlugin;
import org.eclipse.php.internal.debug.core.pathmapper.VirtualPath;
import org.eclipse.php.internal.debug.core.zend.debugger.RemoteDebugger;
import org.eclipse.php.internal.debug.core.zend.debugger.messages.FileContentRequest;
import org.eclipse.php.internal.debug.core.zend.debugger.messages.FileContentResponse;
import org.eclipse.php.internal.debug.core.zend.model.PHPDebugTarget;
import org.eclipse.php.internal.debug.core.zend.model.ResolveBlackList;
/**
* Handle a server request for the delivery of the file content. This class is
* used if debugger protocol is >= 2006040902 New protocol provides new
* message type (StartProcessFileNotification) which allows on-demand path
* mapping and lazy breakpoint sending.
*
* @author michael
*/
public class FileContentRequestCurrentHandler extends AbstractFileContentRequestHandler {
private static final String EXCLUDED_EXTENSION = "phar"; //$NON-NLS-1$
private int reqID;
private String lastFileName;
private String encoding;
private PHPDebugTarget debugTarget;
private boolean isFirstFileToDebug;
private FileContentRequest contentRequest;
public FileContentRequestCurrentHandler() {
isFirstFileToDebug = true;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.php.debug.core.debugger.handlers.IDebugMessageHandler#handle(
* org.eclipse.php.debug.core.debugger.messages.IDebugMessage,
* org.eclipse.php.internal.debug.core.zend.model.PHPDebugTarget)
*/
public void handle(IDebugMessage request, PHPDebugTarget debugTarget) {
this.debugTarget = debugTarget;
contentRequest = (FileContentRequest) request;
reqID = contentRequest.getID();
lastFileName = contentRequest.getFileName();
encoding = contentRequest.getTransferEncoding();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.php.debug.core.debugger.handlers.IDebugRequestHandler#
* getResponseMessage()
*/
public IDebugResponseMessage getResponseMessage() {
FileContentResponse response = new FileContentResponse();
response.setID(reqID);
try {
byte[] content = null;
if (!lastFileName.endsWith(EXCLUDED_EXTENSION)) {
if (isFirstFileToDebug && PHPDebugPlugin.isDummyFile(lastFileName)) {
content = getDummyContent();
// Blacklist dummy.php file, so it won't be requested for
// mapping:
debugTarget.getContextManager().addToResolveBlacklist(new VirtualPath(lastFileName),
ResolveBlackList.Type.FILE);
} else {
RemoteDebugger remoteDebugger = (RemoteDebugger) debugTarget.getRemoteDebugger();
String localPath = remoteDebugger.convertToLocalFilename(lastFileName);
if (localPath != null) {
IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(localPath);
if (resource != null) {
IPath location = resource.getLocation();
if (location != null) {
content = getBytesFromURI(location.toFile().toURI());
} else if (resource.exists()) {
// probably RSE
content = getBytesFromURI(resource.getLocationURI());
}
} else {
File file = new File(localPath);
if (file.exists()) {
content = getBytesFromURI(file.toURI());
}
}
}
}
}
if (content == null) {
content = new byte[0];
}
setResponseContent(response, contentRequest, content);
} catch (FileNotFoundException e) {
// No need to log it. The server will throw an error notification to
// the console indicating that the file was not found.
} catch (NullPointerException e) {
// No need to log it. The server will throw an error notification to
// the console indicating that the file was not found.
} catch (Throwable t) {
Logger.logException("Fail to send the file content to the server", //$NON-NLS-1$
t);
}
isFirstFileToDebug = false;
return response;
}
private String getDebugType() {
String debugType = ""; //$NON-NLS-1$
try {
debugType = debugTarget.getLaunch().getLaunchConfiguration()
.getAttribute(IDebugParametersKeys.PHP_DEBUG_TYPE, ""); //$NON-NLS-1$
} catch (CoreException ce) {
PHPDebugPlugin.log(ce);
}
return debugType;
}
/**
* Returns the dummy content for the current file name.
*/
private byte[] getDummyContent() {
String originalFileName = ""; //$NON-NLS-1$
try {
ILaunchConfiguration launchConfiguration = debugTarget.getLaunch().getLaunchConfiguration();
// The dummy request should be made on the full path of the debugged
// file.
originalFileName = launchConfiguration.getAttribute(IPHPDebugConstants.ATTR_FILE_FULL_PATH, ""); //$NON-NLS-1$
} catch (CoreException e) {
}
StringBuilder contentBuf = new StringBuilder("<?php "); //$NON-NLS-1$
File originalFile = new File(originalFileName);
if (!originalFileName.startsWith("\\\\") && originalFile.exists() //$NON-NLS-1$
&& getDebugType().equals(IDebugParametersKeys.PHP_EXE_SCRIPT_DEBUG)) {
String parentDirectory = originalFile.getParentFile().getAbsolutePath();
if (parentDirectory.endsWith(":\\")) { //$NON-NLS-1$
parentDirectory += "\\"; //$NON-NLS-1$
}
contentBuf.append("chdir('").append(parentDirectory).append("'); "); //$NON-NLS-1$ //$NON-NLS-2$
}
originalFileName = originalFileName.replaceAll("\\\\", "\\\\\\\\"); //$NON-NLS-1$ //$NON-NLS-2$
contentBuf.append("include('").append(originalFileName) //$NON-NLS-1$
.append("'); ?>"); //$NON-NLS-1$
String content = contentBuf.toString();
if (encoding != null) {
try {
return content.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
Logger.logException(
"Failed to create dummy content in the '" //$NON-NLS-1$
+ encoding + "' encoding. \nCreating with the default encoding.", //$NON-NLS-1$
e);
}
}
return content.getBytes();
}
/**
* Read and returns all the bytes from the given file URI
*/
private byte[] getBytesFromURI(URI uri) throws Exception {
IFileStore fileStore = EFS.getStore(uri);
IFileInfo fileInfo = fileStore.fetchInfo();
long length = fileInfo.getLength();
if (length > Integer.MAX_VALUE) {
throw new Exception("The requested file '" + lastFileName + "' is too big"); //$NON-NLS-1$ //$NON-NLS-2$
}
// TODO - There is no handle of file encoding!
byte[] bytes = new byte[(int) length];
InputStream openInputStream = fileStore.openInputStream(EFS.NONE, null);
DataInputStream in = new DataInputStream(openInputStream);
in.readFully(bytes);
in.close();
return bytes;
}
}