Образец API Cisco ThreatGrid Submit ... Как отправить файл образца? - PullRequest
0 голосов
/ 03 апреля 2019

Я не могу успешно вызвать образец API отправки ThreatGrid с использованием Java. Я использовал Java для вызова API в прошлом, поэтому у меня есть опыт настройки этих вызовов.

Я должен отправить сообщение на https://panacea.threatgrid.com/api/v2/samples и указать параметры в теле моего запроса.

Мне также нужно записать файл примера (оцениваемый файл) в тело запроса.

Я понимаю, что мне нужно установить 'Content-Type' в 'multipart / form-data;' и предоставьте граничную строку для разделения частей запроса.

При вызове API отправки я получаю неверный запрос HTTP 400 со следующей ошибкой возврата:

{"api_version":2,"id":7162013,"error":{"message":"The parameter sample is required. ","code":400,"errors":[{"code":400,"message":"The parameter sample is required. ","help":"/doc/main/index.html","report":"support@threatgrid.com"}]}}

Это говорит о том, что я не предоставляю параметр 'sample'. Пример - файл, представляемый для оценки угрозы. Обратите внимание, что моя вторая часть (раздел данных), которую я отправляю в теле запроса, получила имя «образец».

Вот как я устанавливаю заголовки запросов в моем соединении:

    connection.addRequestProperty("Content-Type", "multipart/form-data; boundary=BOUNDARY");
    connection.addRequestProperty("cache-control", "no-cache");
    connection.addRequestProperty("accept", "*/*");
    connection.addRequestProperty("Content-Length", "164784" );
    connection.addRequestProperty("Host", "panacea.threatgrid.com");

Вот пример того, что я пишу в выходной поток соединения:

--BOUNDARY

Content-Disposition: form-data; name="application/json"
{"private":"true","vm":"win7-x64","email_notification":false}

--BOUNDARY

Content-Disposition: form-data; name="sample"; filename="GracePeriod.pdf"
Content-Type: application/pdf

[Bytes of the Sample File being submitted to ThreatGrid api]

--BOUNDARY--

Код, который строит тело моего запроса:

        String boundaryString = "BOUNDARY";
        String LINE_FEED = "\r\n";
        File sampleFileToUpload = new File(fileUrl);

        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes("--" + boundaryString); 
        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes(LINE_FEED);

        outputStream.writeBytes("Content-Disposition: form-data; name=\"application/json\""); 
        outputStream.writeBytes(LINE_FEED);

        //  Build the parameters that get placed into the Header
        Map<String, Object> headers = new HashMap<String, Object>();
        headers.put("private", "true");
        headers.put("vm", "win7-x64");
        headers.put("email_notification", false);   
        Gson gson = new Gson();
        String body = gson.toJson(headers);

        outputStream.writeBytes( body );
        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes(LINE_FEED);

        outputStream.writeBytes("--" + boundaryString);
        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes("Content-Disposition: form-data; name='sample'; filename='"+sampleFileToUpload.getName()+"'");
        outputStream.writeBytes(LINE_FEED);        
        outputStream.writeBytes("Content-Type: application/pdf");
        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes(LINE_FEED);


        //  Write the contents of the file being submitted...
        FileInputStream inputStream  = new FileInputStream(sampleFileToUpload);
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();     
        int nRead;
        byte[] dataArray = new byte[16384];         
        while ((nRead = inputStream.read(dataArray, 0, dataArray.length)) != -1) {
            buffer.write(dataArray, 0, nRead);
        }       
        buffer.flush();
        byte[] bytes  = buffer.toByteArray();           
        inputStream.close();

        outputStream.write(bytes);

        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes(LINE_FEED);

        outputStream.writeBytes("--" + boundaryString + "--");
        outputStream.writeBytes(LINE_FEED);
        outputStream.writeBytes(LINE_FEED);

        outputStream.flush();
        outputStream.close();

Я должен получить сообщение HTTP 200 и ответное сообщение, содержащее подробную информацию о моем представлении.

Надеюсь, кто-то делал это раньше и может показать мне ошибку в моих отношениях.

Спасибо!

РЕДАКТИРОВАТЬ: я забыл упомянуть, что я могу использовать приложение Postman для настройки и успешного вызова этого API. Я установил элементы 'private', 'vm', 'email_notification' и 'sample' в теле запроса как данные формы. Почтальон позволяет вам установить эти элементы в виде текста или файла (есть выпадающий список). В случае «sample» я устанавливаю его в файл, а почтальон позволяет мне «прикрепить» файл. Я использовал консоль Postman, чтобы посмотреть, что отправляется в запросе, и попытался эмулировать это в своем коде Java как можно лучше. Должна быть другая деталь, которая мне нужна, чтобы Почтальон не показывал меня в консоли.

1 Ответ

1 голос
/ 04 апреля 2019

Я наконец смог (слегка окровавленный) заставить API успешно реагировать (HTTP 200 Message). Я предоставлю детали, которые заставили его работать, если это может помочь кому-либо в будущем.

Рассматривая определение API, он заявляет, что «параметры запроса должны быть закодированы как« multipart / form-data »». Я отправлял некоторые параметры в виде данных JSON. Я решил, что мне нужно отправить каждый параметр как отдельную переменную формы, каждый из которых разделен маркером границы (я пытался сделать это раньше, но вернулся к той же идее).

После этого я начал обращать внимание на детализацию пробелов (CRLF) после каждого элемента в теле запроса. API очень чувствителен к тому, как данные форматируются в теле. Я обнаружил, что требуется CRLF перед фактическим значением данных формы, которые вы отправляете.

Вот пример тела запроса, которое я отправляю:

--BOUNDARY
Content-Disposition: form-data; name="private"
[CRLF (a space)]
true
--BOUNDARY
Content-Disposition: form-data; name="vm"
[CRLF (a space)]
win7-x64
--BOUNDARY
Content-Disposition: form-data; name="email_notification"
[CRLF (a space)]
false
--BOUNDARY
Content-Disposition: form-data; name="sample"; 
filename="CourseCompletionCertificate.pdf"
Content-Type: application/pdf
[CRLF (a space)]
[data stream of the Sample file in a byte array...]
--BOUNDARY--

Я нашел примеры multipart / form-data, и я заметил использование CRLF в данных, и я приложил все усилия, чтобы скопировать способ отправки этих данных. Именно после этой детали API ответил успешно.

...