codenameone

Obtain Header information from ConnectionRequest (Content-Disposition)


Using the below code I am able to download and save a file from a remote server based on certain filters. I use the ConnectionRequest to make a post request to the server. This works well. However I need to get at some header information of the request and am struggling.

private void handleDownload(String module, String filtersJson) {
    Log.p("Handling download for URL: " + "https://website/api/csv/"+module);

    String postUrl = "https://website/api/csv/"+module;



    try {

        
        JSONParser parser = new JSONParser();
        Map<String, Object> parsedResult = parser.parseJSON(new StringReader(filtersJson));

        ConnectionRequest request = new ConnectionRequest(postUrl, true);

        request.addArgument("Filters[FilterAll]", (String) parsedResult.get("FilterAll"));
        for (int i = 0; i <= 31; i++) {
            String key = "Filter" + i;
            request.addArgument("Filters[" + key + "]", (String) parsedResult.get(key));
        }
        request.addArgument("Filters[To]", (String) parsedResult.get("To"));
        request.addArgument("Filters[From]", (String) parsedResult.get("From"));
        request.addArgument("Filters[UseDat]", (String) parsedResult.get("UseDat"));
        request.addArgument("order[0][column]", "0");
        request.addArgument("order[0][dir]", "desc");
        request.addArgument("search[value]", "");
        request.setFailSilently(true);
        request.setReadResponseForErrors(true);
        request.addRequestHeader("Authorization", "Bearer " + eventsToken);
        request.setTimeout(10000);
        request.addResponseListener(evt -> {
            if (request.getResponseCode() == 200) {

        String fileName = "CSVModule"+ postUrl.substring(postUrl.lastIndexOf('/') + 1);
        String saveDirectory = FileSystemStorage.getInstance().getAppHomePath() + fileName + ".xlsx";

//                    =NOT SUPPORTED=
//                    String disposition = request.getHeaderField("Content-Disposition");

                Display.getInstance().callSerially(() -> {
                    try (OutputStream outputStream = FileSystemStorage.getInstance().openOutputStream(saveDirectory)) {

                        int bufferSize = 4096;
                        byte[] buffer = new byte[bufferSize];
                        int bytesRead;

                        
                        InputStream inputStream = new ByteArrayInputStream(request.getResponseData());
                        while ((bytesRead = inputStream.read(buffer)) != -1) {
                            outputStream.write(buffer, 0, bytesRead);
                        }
                        //TODO add progress bar instead of below Toastbar
                        ToastBar.Status status = ToastBar.getInstance().createStatus();
                        status.setMessage("File downloaded");
                        status.setExpires(3000);  // only show the status for 3 seconds, then have it automatically clear
                        status.show();

                        Log.p("File successfully downloaded to: " + saveDirectory);
                    } catch (Exception e) {
                        Log.e(e);
                    }
                    System.out.println("File downloaded and saved as: " + saveDirectory);
                });
            } else {
                Log.p("Failed to download file: " + request.getResponseErrorMessage());
            }
        });

        NetworkManager.getInstance().addToQueueAndWait(request);
    }
    catch (Exception e) {
        e.printStackTrace();
    }

}

I'd like to retrieve the Content-Disposition header so I can add the correct file name to save. Something like the line: -

String disposition = request.getHeaderField("Content-Disposition");

but this is not supported. How can I achieve this?


Solution

  • You do that by overriding readHeaders e.g.:

    class MyConnectionRequest extends ConnectionRequest {
        public String contentDisposition;
        public MyConnectionRequest(String postUrl) {
            super(postUrl, true);
        }
    
        
        protected void readHeaders(Object connection) throws IOException {
            contentDisposition = request.getHeader(connection, "Content-Disposition");
        }
    }
    

    Then you can use this connection request as you did before and the field should be initialized correctly.

    FYI There's a simpler API for these requests called the Rest API which enables more fluent header access.