2

I want to upload a file as described here: http://docs.octoprint.org/en/master/api/files.html#upload-file-or-create-folder

I use apache-httpclient to send a post connection, but whenever I start the method, nothing happens and the application got stuck without error, but just doesn't do anything.

Other POST and GET requests are working and I don't need an API-Key because I turned off the authentication

CloseableHttpClient posterClient = HttpClients.createDefault();
        HttpPost post = new HttpPost("http://localhost:5002/api/files/local");
        post.setHeader("Host", "http://localhost:5002");
        post.setHeader("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundaryDeC2E3iWbTv1PwMC");

        post.setHeader("X-Api-Key", "");


        HttpEntity entity = MultipartEntityBuilder
                .create()

                .addBinaryBody("file", new File("/Users/florian/eclipse-workspace/docker-Client/src/main/java/test/dog3.gcode"), ContentType.create("multipart/form-data"), "dog.gcode")
                .addTextBody("select", "true")
                .addTextBody("print", "true")
                .build();


        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        entity.writeTo(bytes);
        String content = bytes.toString();
        StringEntity entity2 = new StringEntity(content, ContentType.APPLICATION_OCTET_STREAM);
        entity2.setContentEncoding("application/octet-stream");
        post.setEntity(entity2);
        CloseableHttpResponse answer = posterClient.execute(post);

If I print the POST, I'll get (the gcode-instructions deleted):


RequestLine:POST http://localhost:5002/api/files/local HTTP/1.1
Header:boundary=----WebKitFormBoundaryDeC2E3iWbTv1PwMC;
Content:--JIDzHYxyG74480VXGugHYTI-7xe5OrZ8
Content-Disposition: form-data; name="file"; filename="dog.gcode"
Content-Type: multipart/form-data
Content-Transfer-Encoding: binary

M5
G90
G21
G1 F3000
G1  X18.0359 Y51.0881
M3 S90
G4 P0.3

--JIDzHYxyG74480VXGugHYTI-7xe5OrZ8
Content-Disposition: form-data; name="select"
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit

true
--JIDzHYxyG74480VXGugHYTI-7xe5OrZ8
Content-Disposition: form-data; name="print"
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit

true
--JIDzHYxyG74480VXGugHYTI-7xe5OrZ8--

So... not exactly what I want...

Flontis
  • 307
  • 1
  • 4
  • 13
  • Does the target folder exist? If so, do you have permission to write on it? – rbento Aug 25 '19 at 17:48
  • yes, the folder exists and I have writing permission (as I have admin permissions due to disabled authentication). I guess I'm missing some details in the building of the request... – Flontis Aug 25 '19 at 17:52
  • I am reading the code and comparing to the documentation, so far I don't see any issues. Yes, I would print the request to check the headers with the documentation in this case. – rbento Aug 25 '19 at 17:54
  • I see you have a docker-client in your file path. Are you using docker? If so can you try without the container? Try locally first to avoid any container configuration issues. – rbento Aug 25 '19 at 18:00
  • Just getting "POST http://localhost:5002/api/files/local HTTP/1.1" if I do print(post)... – Flontis Aug 25 '19 at 18:04
  • "docker-client" is just the name of the project – Flontis Aug 25 '19 at 18:04
  • I see, you should print the headers though, and should see something similar to the documentation, with the boundaries and all. I will try to set up a project here in a few. – rbento Aug 25 '19 at 18:07
  • Today I ran OctoPrint in a docker container and tested with a REST Client tool before doing any code. I got to a point where the REST endpoint expects a POST with Content-Type application/json, which means the file needs to be base64 encoded in the body. Also you need to either have a folder or create one. I created a folder in the GUI application so the endpoint for the post would be "/api/files/local/docs". Alternatively you need to also pass "foldername" to create a folder. Think about this: Try to get it working using an app like Postman first then it would be easy to adjust the code. – rbento Aug 26 '19 at 04:31
  • Trying out Postman now. I can do some GET-Requests, but how do I specify the Content-Disposition fields of a multipart/form-data in Postman? – Flontis Aug 26 '19 at 11:43

1 Answers1

2

Okay by now my code looks like this and it works. To delete unnecessary lines like Content-Type-Encoding, you have to set the ode to "browser-compatible"

CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpEntity entity = MultipartEntityBuilder.create().setMode(
HttpMultipartMode.BROWSER_COMPATIBLE).setBoundary("----WebKitFormBoundaryDeC2E3iWbTv1PwMC").setContentType(
ContentType.MULTIPART_FORM_DATA)
                .addBinaryBody("file",
                        new File("PATH"),
                        ContentType.APPLICATION_OCTET_STREAM, "filename.gcode")
                .addTextBody("select", "true", ContentType.MULTIPART_FORM_DATA).addTextBody("print", "true", ContentType.MULTIPART_FORM_DATA)
                .build();

        HttpPost httpPost = new HttpPost("http://localhost:5002/api/files/local");
        httpPost.addHeader("Host", "http://localhost:5002");
        httpPost.addHeader("X-Api-Key", "88CC15F3B5864CCAB19981A8B67A4071");
        httpPost.addHeader("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundaryDeC2E3iWbTv1PwMC");
        httpPost.setEntity(entity);
        //betterPrint(httpPost);
        HttpResponse response = httpClient.execute(httpPost);

        HttpEntity result = response.getEntity();
Flontis
  • 307
  • 1
  • 4
  • 13