I'm trying to upload a file to OneDrive using the REST API. The code below opens a socket to the OneDrive host and feeds it the payload from the example in the OneDrive doc, but OneDrive returns a 400 status with an "Invalid Verb" message.
I know the access token is valid because the GET call works. The access token has the following scopes: wl.offline_access
, wl.skydrive_update
.
I've tried GETting, PUTting and POSTing to other folders and the GETs work but PUTs and POSTs fail. Before using the socket I tried PUTs and POSTs using Jersey's WebResource
, java's HttpUrlConnection
, apache's HttpClient
, and curl
. OneDrive responds with different error message based on the verb/library pairing.
I've sent requests to a local server that dumped the payload so I could verify that there's no problem with the socket code. It is sending the exact message from the doc, but with whitespace replaced with control characters.
import java.io.PrintWriter;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class OneDriveUploadTest {
public static void main(String[] args) throws Exception {
String accessToken = "...";
// this works
// String data = "GET https://apis.live.net/v5.0/me/skydrive/files?access_token="+accessToken+"\r\n\r\n";
// this fails
String data = "POST https://apis.live.net/v5.0/me/skydrive/files?access_token="+accessToken+"\r\n\r\n--A300x\r\nContent-Disposition: form-data; name=\"file\"; filename=\"HelloWorld.txt\"\r\n\nContent-Type: application/octet-stream\r\nHello, World!\r\n--A300x--\r\n\r\n";
// this also fails
// String data = "PUT https://apis.live.net/v5.0/me/skydrive/files/HelloWorld.txt?access_token="+accessToken+"\r\n\r\nHello, World!\r\n\r\n";
SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
Socket socket = (SSLSocket) socketFactory.createSocket("apis.live.net", 443);
PrintWriter sout = new PrintWriter(socket.getOutputStream());
sout.print(data);
sout.flush();
InputStream sin = socket.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(sin));
String line;
while ((line = rd.readLine()) != null) {
System.out.println("got: " + line);
}
sin.close();
sout.close();
socket.close();
}
}
I hate to answer my own question but I found something that works. This code uploads a file to OneDrive with a PUT using Apache's HttpClient.
import java.io.File;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.HttpResponse;
import org.apache.http.entity.FileEntity;
import org.apache.http.client.methods.HttpPut;
public class OneDriveHttpClientUpload {
public static void main(String[] args) throws Exception {
String accessToken = "...";
String url = "https://apis.live.net/v5.0/me/skydrive/files/HelloWorld.txt?access_token="+accessToken;
HttpClient apClient = HttpClients.createDefault();
HttpPut httpPut = new HttpPut(url);
FileEntity file = new FileEntity(new File("testfile.txt"));
httpPut.setEntity(file);
HttpResponse ret = apClient.execute(httpPut);
}
}