// Copyright (c) 2015-2021 Vector 35 Inc // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. #pragma once #include #include #include #include #include #include #include #include "binaryninjaapi.h" namespace BinaryNinja::Http { enum ResponseCode { Continue = 100, SwitchingProtocols = 101, OK = 200, Created = 201, Accepted = 202, NonAuthoritativeInformation = 203, NoContent = 204, ResetContent = 205, PartialContent = 206, MultipleChoices = 300, MovedPermanently = 301, Found = 302, SeeOther = 303, NotModified = 304, UseProxy = 305, TemporaryRedirect = 307, BadRequest = 400, Unauthorized = 401, PaymentRequired = 402, Forbidden = 403, NotFound = 404, MethodNotAllowed = 405, NotAcceptable = 406, ProxyAuthenticationRequired = 407, RequestTimeout = 408, Conflict = 409, Gone = 410, LengthRequired = 411, PreconditionFailed = 412, RequestEntityTooLarge = 413, RequestURITooLong = 414, UnsupportedMediaType = 415, RequestedRangeNotSatisfiable = 416, ExpectationFailed = 417, ImATeapot = 418, InternalServerError = 500, NotImplemented = 501, BadGateway = 502, ServiceUnavailable = 503, GatewayTimeout = 504, HTTPVersionNotSupported = 505, }; /*! Basic HTTP response structure */ struct Response { BinaryNinja::DownloadInstance::Response response; std::vector body; std::string error; /*! Get response body as uint8_t vector \return Response body bytes */ std::vector GetRaw() const noexcept; /*! Get response body as text string \return Response body string */ std::string GetString() const noexcept; /*! Get response body as a json value \return Response body json \throws runtime_error On JSON parse error */ Json::Value GetJson() const; /*! Get response body as a json value without throwing \param value Output json value \return True if successful */ bool GetJson(Json::Value& value) const noexcept; }; /*! Structure for multipart form fields */ struct MultipartField { std::string name; std::vector content; std::optional filename; /*! Construct a Multipart Field structure with a UTF-8 string encoded body \param name Name of the field to be sent in a POST request \param content Contents of the field */ MultipartField(std::string name, const std::string& content): name(std::move(name)), content({}), filename({}) { std::copy(content.begin(), content.end(), std::back_inserter(this->content)); } /*! Construct a Multipart Field structure for a file with a UTF-8 string encoded body \param name Name of the field to be sent in a POST request \param content Contents of the field \param filename Filename associated with the contents */ MultipartField(std::string name, const std::string& content, std::string filename): name(std::move(name)), content({}), filename(std::move(filename)) { std::copy(content.begin(), content.end(), std::back_inserter(this->content)); } /*! Construct a Multipart Field structure with a binary blob body \param name Name of the field to be sent in a POST request \param content Contents of the field */ MultipartField(std::string name, std::vector content): name(std::move(name)), content(std::move(content)), filename({}) { } /*! Construct a Multipart Field structure for a file with a binary blob body \param name Name of the field to be sent in a POST request \param content Contents of the field \param filename Filename associated with the contents */ MultipartField(std::string name, std::vector content, std::string filename): name(std::move(name)), content(std::move(content)), filename(std::move(filename)) { } }; /*! Structure containing HTTP metadata for requests */ struct Request { std::string m_method; std::string m_url; std::unordered_map m_headers; std::vector m_body; std::function m_downloadProgress; std::function m_uploadProgress; /*! Construct an arbitrary HTTP request with an empty body \param method Request method eg GET \param url Target URL eg https://binary.ninja \param headers Header keys/values \param params Query parameters, keys/values \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates */ Request(std::string method, std::string url, std::unordered_map headers = {}, std::vector> params = {}, std::function downloadProgress = {}, std::function uploadProgress = {}); /*! Construct an arbitrary HTTP request with a binary data body \param method Request method eg GET \param url Target URL eg https://binary.ninja \param headers Header keys/values \param params Query parameters, keys/values \param body Content body (binary data) \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates */ Request(std::string method, std::string url, std::unordered_map headers, std::vector> params, std::vector body, std::function downloadProgress = {}, std::function uploadProgress = {}); /*! Construct an arbitrary HTTP request with url encoded form fields as the body \param method Request method eg GET \param url Target URL eg https://binary.ninja \param headers Header keys/values \param params Query parameters, keys/values \param formFields HTTP form fields, keys/values (both must be strings) \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates */ Request(std::string method, std::string url, std::unordered_map headers, std::vector> params, std::vector> formFields, std::function downloadProgress = {}, std::function uploadProgress = {}); /*! Construct an arbitrary HTTP request with Multipart encoded form fields as the body \param method Request method eg GET \param url Target URL eg https://binary.ninja \param headers Header keys/values \param params Query parameters, keys/values \param formFields HTTP form fields, keys/values (values can be arbitrary data) \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates */ Request(std::string method, std::string url, std::unordered_map headers, std::vector> params, std::vector formFields, std::function downloadProgress = {}, std::function uploadProgress = {}); /*! Construct an HTTP GET request \param url Target URL eg https://binary.ninja \param headers Header keys/values \param params Query parameters, keys/values \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates \return Request structure with specified fields */ static Request Get(std::string url, std::unordered_map headers = {}, std::vector> params = {}, std::function downloadProgress = {}, std::function uploadProgress = {}); /*! Construct an HTTP POST request with a binary data body \param url Target URL eg https://binary.ninja \param headers Header keys/values \param params Query parameters, keys/values \param body Request body data \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates \return Request structure with specified fields */ static Request Post(std::string url, std::unordered_map headers = {}, std::vector> params = {}, std::vector body = {}, std::function downloadProgress = {}, std::function uploadProgress = {}); /*! Construct an HTTP POST request with url encoded form fields as the body \param url Target URL eg https://binary.ninja \param headers Header keys/values \param params Query parameters, keys/values \param formFields HTTP form fields, keys/values (both must be strings) \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates \return Request structure with specified fields */ static Request Post(std::string url, std::unordered_map headers, std::vector> params, std::vector> formFields, std::function downloadProgress = {}, std::function uploadProgress = {}); /*! Construct an HTTP POST request with Multipart encoded form fields as the body \param url Target URL eg https://binary.ninja \param headers Header keys/values \param params Query parameters, keys/values \param formFields HTTP form fields, keys/values (values can be arbitrary data) \param downloadProgress Function to call for download progress updates \param uploadProgress Function to call for upload progress updates \return Request structure with specified fields */ static Request Post(std::string url, std::unordered_map headers, std::vector> params, std::vector formFields, std::function downloadProgress = {}, std::function uploadProgress = {}); }; /*! Convert a string to a URLEncoded form-field safe form \param str Input string \return URLEncoded string */ std::string UrlEncode(const std::string& str); /*! Convert a list of key/value pair strings into a URLEncoded form body \param fields Input key/value pairs \return URLEncoded form body */ std::string UrlEncode(const std::vector>& fields); /*! Convert a list of form fields (potentially containing binary data) into a multipart encoded form body \param fields Input fields \param boundary Output boundary between fields in the body (for Content-Type header) \return Multipart encoded form body */ std::vector MultipartEncode(const std::vector& fields, std::string& boundary); /*! Perform an HTTP request as specified by a Request, storing results in a Response \param instance DownloadInstance instance \param request Input Request structure with fields \param response Output Response structure with body \return Zero or greater on success */ int Perform(const BinaryNinja::Ref& instance, const Request& request, Response& response); }