| /******************************************************************************* |
| * Copyright (c) 2004 Composent, Inc. 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: Composent, Inc. - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.ecf.provider.filetransfer.retrieve; |
| |
| import java.io.IOException; |
| import java.net.ConnectException; |
| import java.net.URL; |
| import java.net.URLConnection; |
| |
| import org.eclipse.ecf.core.identity.ID; |
| import org.eclipse.ecf.core.security.IConnectContext; |
| import org.eclipse.ecf.core.util.Proxy; |
| import org.eclipse.ecf.filetransfer.IFileRangeSpecification; |
| import org.eclipse.ecf.filetransfer.IFileTransferPausable; |
| import org.eclipse.ecf.filetransfer.IncomingFileTransferException; |
| import org.eclipse.ecf.filetransfer.InvalidFileRangeSpecificationException; |
| import org.eclipse.ecf.filetransfer.identity.IFileID; |
| import org.eclipse.ecf.internal.provider.filetransfer.Messages; |
| import org.eclipse.osgi.util.NLS; |
| |
| public class UrlConnectionRetrieveFileTransfer extends |
| AbstractRetrieveFileTransfer { |
| |
| private static final int HTTP_RANGE_RESPONSE = 206; |
| |
| private static final int OK_RESPONSE_CODE = 200; |
| |
| protected URLConnection urlConnection; |
| |
| // XXX currently unused |
| protected IConnectContext connectContext; |
| // XXX currently unused |
| protected Proxy proxy; |
| |
| protected long lastModifiedTime = 0L; |
| |
| protected int httpVersion = 1; |
| |
| protected int responseCode = -1; |
| |
| protected String responseMessage = null; |
| |
| protected IFileID fileid = null; |
| |
| protected void connect() throws IOException { |
| urlConnection = getRemoteFileURL().openConnection(); |
| } |
| |
| protected boolean isConnected() { |
| return (urlConnection != null); |
| } |
| |
| protected void setResumeRequestHeaderValues() throws IOException { |
| if (this.bytesReceived <= 0 || this.fileLength <= this.bytesReceived) |
| throw new IOException( |
| Messages.UrlConnectionRetrieveFileTransfer_RESUME_START_ERROR); |
| setRangeHeader("bytes=" + this.bytesReceived + "-"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| protected void setRequestHeaderValues() |
| throws InvalidFileRangeSpecificationException { |
| final IFileRangeSpecification rangeSpec = getFileRangeSpecification(); |
| if (rangeSpec != null && isHTTP()) { |
| final long startPosition = rangeSpec.getStartPosition(); |
| final long endPosition = rangeSpec.getEndPosition(); |
| if (startPosition < 0) |
| throw new InvalidFileRangeSpecificationException( |
| Messages.UrlConnectionRetrieveFileTransfer_RESUME_START_POSITION_LESS_THAN_ZERO, |
| rangeSpec); |
| if (endPosition != -1L && endPosition <= startPosition) |
| throw new InvalidFileRangeSpecificationException( |
| Messages.UrlConnectionRetrieveFileTransfer_RESUME_ERROR_END_POSITION_LESS_THAN_START, |
| rangeSpec); |
| setRangeHeader("bytes=" + startPosition + "-" + ((endPosition == -1L) ? "" : ("" + endPosition))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
| } |
| } |
| |
| private void setRangeHeader(String value) { |
| urlConnection.setRequestProperty("Range", value); //$NON-NLS-1$ |
| } |
| |
| public int getResponseCode() { |
| if (responseCode != -1) |
| return responseCode; |
| if (isHTTP()) { |
| final String response = urlConnection.getHeaderField(0); |
| if (response == null) { |
| responseCode = -1; |
| httpVersion = 1; |
| return responseCode; |
| } |
| if (response == null || !response.startsWith("HTTP/")) //$NON-NLS-1$ |
| return -1; |
| response.trim(); |
| final int mark = response.indexOf(" ") + 1; //$NON-NLS-1$ |
| if (mark == 0) |
| return -1; |
| if (response.charAt(mark - 2) != '1') |
| httpVersion = 0; |
| int last = mark + 3; |
| if (last > response.length()) |
| last = response.length(); |
| responseCode = Integer.parseInt(response.substring(mark, last)); |
| if (last + 1 <= response.length()) |
| responseMessage = response.substring(last + 1); |
| } else { |
| responseCode = OK_RESPONSE_CODE; |
| responseMessage = "OK"; //$NON-NLS-1$ |
| } |
| |
| return responseCode; |
| |
| } |
| |
| private boolean isHTTP() { |
| final String protocol = getRemoteFileURL().getProtocol(); |
| if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) //$NON-NLS-1$ //$NON-NLS-2$ |
| return true; |
| return false; |
| } |
| |
| private boolean isHTTP11() { |
| return (isHTTP() && httpVersion >= 1); |
| } |
| |
| protected void getResponseHeaderValues() throws IOException { |
| if (!isConnected()) |
| throw new ConnectException( |
| Messages.UrlConnectionRetrieveFileTransfer_CONNECT_EXCEPTION_NOT_CONNECTED); |
| if (getResponseCode() == -1) |
| throw new IOException( |
| Messages.UrlConnectionRetrieveFileTransfer_EXCEPTION_INVALID_SERVER_RESPONSE); |
| lastModifiedTime = urlConnection.getLastModified(); |
| setFileLength(urlConnection.getContentLength()); |
| } |
| |
| protected void getResumeResponseHeaderValues() throws IOException { |
| if (!isConnected()) |
| throw new ConnectException( |
| Messages.UrlConnectionRetrieveFileTransfer_CONNECT_EXCEPTION_NOT_CONNECTED); |
| if (getResponseCode() != HTTP_RANGE_RESPONSE) |
| throw new IOException( |
| Messages.UrlConnectionRetrieveFileTransfer_INVALID_SERVER_RESPONSE_TO_PARTIAL_RANGE_REQUEST); |
| if (lastModifiedTime != urlConnection.getLastModified()) |
| throw new IOException( |
| Messages.UrlConnectionRetrieveFileTransfer_EXCEPTION_FILE_MODIFIED_SINCE_LAST_ACCESS); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer#openStreams() |
| */ |
| protected void openStreams() throws IncomingFileTransferException { |
| try { |
| connect(); |
| setRequestHeaderValues(); |
| // Make actual GET request |
| setInputStream(urlConnection.getInputStream()); |
| getResponseHeaderValues(); |
| fireReceiveStartEvent(); |
| } catch (final Exception e) { |
| throw new IncomingFileTransferException( |
| NLS |
| .bind( |
| Messages.UrlConnectionRetrieveFileTransfer_EXCEPTION_COULD_NOT_CONNECT, |
| getRemoteFileURL().toString()), e); |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer#hardClose() |
| */ |
| protected void hardClose() { |
| super.hardClose(); |
| urlConnection = null; |
| responseCode = -1; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setConnectContextForAuthentication(org.eclipse.ecf.core.security.IConnectContext) |
| */ |
| public void setConnectContextForAuthentication( |
| IConnectContext connectContext) { |
| this.connectContext = connectContext; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setProxy(org.eclipse.ecf.core.util.Proxy) |
| */ |
| public void setProxy(Proxy proxy) { |
| this.proxy = proxy; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer#doPause() |
| */ |
| protected boolean doPause() { |
| if (isPaused() || !isConnected() || isDone()) |
| return false; |
| this.paused = true; |
| return this.paused; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer#doResume() |
| */ |
| protected boolean doResume() { |
| if (!isPaused() || isConnected()) |
| return false; |
| return openStreamsForResume(); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer#getAdapter(java.lang.Class) |
| */ |
| public Object getAdapter(Class adapter) { |
| if (adapter == null) |
| return null; |
| if (adapter.equals(IFileTransferPausable.class) && isHTTP11()) |
| return this; |
| else |
| return super.getAdapter(adapter); |
| } |
| |
| /** |
| * @return |
| */ |
| private boolean openStreamsForResume() { |
| final URL theURL = getRemoteFileURL(); |
| try { |
| remoteFileURL = new URL(theURL.toString()); |
| connect(); |
| setResumeRequestHeaderValues(); |
| // Make actual GET request |
| setInputStream(urlConnection.getInputStream()); |
| getResumeResponseHeaderValues(); |
| this.paused = false; |
| fireReceiveResumedEvent(); |
| return true; |
| } catch (final Exception e) { |
| this.exception = e; |
| this.done = true; |
| hardClose(); |
| fireTransferReceiveDoneEvent(); |
| return false; |
| } |
| } |
| |
| public ID getID() { |
| return fileid; |
| } |
| |
| } |