Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cadc-util/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ sourceCompatibility = 1.8

group = 'org.opencadc'

version = '1.12.17'
version = '1.12.18'

description = 'OpenCADC core utility library'
def git_url = 'https://github.com/opencadc/core'
Expand Down
97 changes: 81 additions & 16 deletions cadc-util/src/main/java/ca/nrc/cadc/net/HttpUpload.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,19 @@ public class HttpUpload extends HttpTransfer {
private InputStream istream;
private OutputStreamWrapper wrapper;
private FileContent fileContent;

private HttpURLConnection conn;
private boolean isCallerDriven = false;

/**
* Construct an HttpUpload for caller-driven mode.
* Usage: Write to getOutputStream(), then call finish() to close the connection.
* Note: run() or prepare() can't be used with this constructor because nothing is provided upfront to write.
*/
public HttpUpload(URL url) {
super(url, false);
isCallerDriven = true;
}

public HttpUpload(File src, URL dest) {
super(dest, false);
this.localFile = src;
Expand Down Expand Up @@ -225,6 +237,9 @@ public void prepare()
TransientException, IOException, InterruptedException,
RangeNotSatisfiableException {
boolean ok = false;
if (isCallerDriven) {
throw new IllegalStateException("prepare() not allowed for caller-driven mode");
}
try {
doActionWithRetryLoop();
ok = true;
Expand All @@ -243,6 +258,9 @@ protected void doAction()
ResourceAlreadyExistsException, ResourceNotFoundException,
TransientException, IOException, InterruptedException {
log.debug(this.toString());
if (isCallerDriven) {
throw new IllegalStateException("run() not allowed for caller-driven mode");
}
if (!go) {
return; // cancelled while queued, event notification handled in terminate()
}
Expand All @@ -253,21 +271,9 @@ protected void doAction()

fireEvent(TransferEvent.CONNECTING);

HttpURLConnection conn = (HttpURLConnection) this.remoteURL.openConnection();
super.setRequestOptions(conn);
conn.setRequestMethod("PUT");
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);

setRequestHeaders(conn);
setRequestAuthHeaders(conn);
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection sslConn = (HttpsURLConnection) conn;
initHTTPS(sslConn);
}
openConnection();

doPut(conn);
doPut();
this.responseStream = conn.getInputStream();
log.debug("completed");
fireEvent(TransferEvent.COMPLETED);
Expand All @@ -286,7 +292,7 @@ protected void doAction()
}
}

private void doPut(HttpURLConnection conn)
private void doPut()
throws AccessControlException, NotAuthenticatedException,
ByteLimitExceededException, ExpectationFailedException,
IllegalArgumentException, PreconditionFailedException,
Expand Down Expand Up @@ -369,4 +375,63 @@ private void doPut(HttpURLConnection conn)

checkErrors(remoteURL, conn);
}

/**
* Open the upload connection and return the OutputStream to write the
* request body to.
* This method opens the connection immediately.
* Use this instead of run() when you want to write to the connection
* directly rather than supplying an InputStream up front.
*
* @return the OutputStream of the underlying HttpURLConnection
* @throws IOException if the connection cannot be opened
*/
public OutputStream getOutputStream() throws IOException {
if (!isCallerDriven) {
throw new IllegalStateException("Caller-driven mode is off for this HttpUpload instance. Use run() or prepare() instead.");
}
if (conn == null) {
openConnection();
}
return conn.getOutputStream();
}

private void openConnection() throws IOException {
conn = (HttpURLConnection) this.remoteURL.openConnection();
super.setRequestOptions(conn);
conn.setRequestMethod("PUT");
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);

setRequestHeaders(conn);
setRequestAuthHeaders(conn);
if (conn instanceof HttpsURLConnection) {
HttpsURLConnection sslConn = (HttpsURLConnection) conn;
initHTTPS(sslConn);
}
}

/**
* Note: Must only be called after getOutputStream() and after the stream has been
* closed. Must not be called if run() or prepare() was used instead.
*
* @throws IllegalStateException if connection is not open
* @throws IOException on network errors reading the response
*/
public void finish() throws AccessControlException, NotAuthenticatedException,
ExpectationFailedException, IllegalArgumentException,
PreconditionFailedException, ResourceAlreadyExistsException, ResourceNotFoundException,
TransientException, IOException, InterruptedException, RangeNotSatisfiableException {
if (conn == null) {
throw new IllegalStateException("no connection to close");
}
try {
checkErrors(remoteURL, conn);
} finally {
conn.disconnect();
conn = null;
}

}
}
Loading