package com.limegroup.gnutella.uploader;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Locale;
import org.apache.http.HttpException;
import org.apache.http.HttpStatus;
import org.apache.http.protocol.HttpContext;
import org.limewire.util.StringUtils;
import com.limegroup.gnutella.URN;
import com.limegroup.gnutella.http.HTTPConstants;
import com.limegroup.gnutella.library.FileDesc;
import com.limegroup.gnutella.library.FileView;
import com.limegroup.gnutella.uploader.authentication.HttpRequestFileViewProvider;
/**
* Provides methods for parsing Gnutella request URIs.
*/
class FileRequestParser {
/** The type of the requested resource. */
enum RequestType {
/** Indicates a request for a file transfer. */
FILE,
/** Indicates a request for a THEX tree. */
THEX
};
/**
* Parses a URN request.
* @param uri the <tt>String</tt> instance containing the get request
*
* @return information about the requested file, <code>null</code> if the
* request type is invalid or the URN does not map to a valid file
* @throws IOException thrown if the request is malformed
* @throws HttpException
*/
public static FileRequest parseRequest(HttpRequestFileViewProvider fileListProvider, final String uri,
HttpContext context) throws IOException, com.limegroup.gnutella.uploader.HttpException {
// Only parse URI requests.
int index = uri.toLowerCase(Locale.US).indexOf("/uri-res/");
if(index == -1) {
throw new IOException("invalid request");
}
String uriRes = uri.substring(index);
URN urn = URN.createSHA1UrnFromHttpRequest(uriRes + " HTTP/1.1");
// Parse the service identifier, whether N2R, N2X or something
// we cannot satisfy. URI scheme names are not case-sensitive.
RequestType requestType;
String requestUpper = uriRes.toUpperCase(Locale.US);
if (requestUpper.indexOf(HTTPConstants.NAME_TO_THEX) > 0) {
requestType = RequestType.THEX;
} else if (requestUpper.indexOf(HTTPConstants.NAME_TO_RESOURCE) > 0) {
requestType = RequestType.FILE;
} else {
return null;
}
FileDesc desc = null;
String friendID = index == 0 ? null : parseFriendId(uri.substring(0, index));
for (FileView fileList : fileListProvider.getFileViews(friendID, context)) {
desc = fileList.getFileDesc(urn);
if (desc != null) {
break;
}
}
if(desc == null) {
return null;
} else {
return new FileRequest(desc, requestType, friendID);
}
}
static String parseFriendId(String uriString) throws com.limegroup.gnutella.uploader.HttpException {
try {
URI uri = new URI(uriString);
String path = uri.getPath();
if (path == null) {
throw new com.limegroup.gnutella.uploader.HttpException("no friend id:", HttpStatus.SC_BAD_REQUEST);
}
if (path.endsWith("/")) {
int previousSlash = path.lastIndexOf('/', path.length() - 2);
if (previousSlash != -1) {
return path.substring(previousSlash + 1, path.length() - 1);
}
} else {
int lastSlash = path.lastIndexOf('/');
if (lastSlash != -1) {
return path.substring(lastSlash + 1);
}
}
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
throw new com.limegroup.gnutella.uploader.HttpException("no friend id:", HttpStatus.SC_BAD_REQUEST);
}
/** Record for storing information about a file request. */
static class FileRequest {
private final FileDesc fileDesc;
private final String friendID;
/** Type of the requested resource. */
private final RequestType requestType;
public FileRequest(FileDesc fileDesc, RequestType requestType, String friendID) {
this.fileDesc = fileDesc;
this.requestType = requestType;
this.friendID = friendID;
}
public boolean isThexRequest() {
return this.requestType == RequestType.THEX;
}
public FileDesc getFileDesc() {
return fileDesc;
}
public String getFriendID() {
return friendID;
}
@Override
public String toString() {
return StringUtils.toString(this);
}
}
}