URL rejected: Malformed input to a URL function. Closing connection

Hi, team!

I’ve edited GitHub - binance/binance-signature-examples: Examples of generating HMAC and RSA signature for Binance API C++ example with my data and after running it:

  /*
  ### public data endpoint, call send_public_request #####
  get klines
  */
  parameters.insert({
      {"symbol", "BTCUSDT"},
      {"interval", "1d"},
      {"limit", "10"}});

  sendPublicRequest(curl, "/api/v3/klines", parameters);

  /*
  get account informtion
  if you can see the account details, then the API key/secret is correct
  */
  sendSignedRequest(curl, "GET", "/api/v3/account", parameters);

sendPublicRequest function works fine, but

sendSignedRequest function cause an error:

  • URL rejected: Malformed input to a URL function
  • Closing connection
    curl_easy_perform() failed: URL using bad/illegal format or missing URL
    , URL rejected: Malformed input to a URL function

Could you please give me a hint what can be the cause of it?

Thanks!

/*

public data endpoint, call send_public_request

get klines
*/
parameters.insert({
{“symbol”, “BTCUSDT”},
{“interval”, “1d”},
{“limit”, “10”}});

sendPublicRequest(curl, “/api/v3/klines”, parameters);

/*
get account information
if you can see the account details, then the API key/secret is correct
*/
// Error: Using ‘parameters’ meant for ‘klines’ endpoint which may not have necessary info for ‘account’ endpoint
// sendSignedRequest(curl, “GET”, “/api/v3/account”, parameters);
// Corrected: Clear or create a new map for appropriate parameters for account information
parameters.clear(); // Correction: Clear existing parameters to ensure correct and relevant data for account endpoint
sendSignedRequest(curl, “GET”, “/api/v3/account”, parameters);

The parameters map used in the sendPublicRequest function for the /api/v3/klines endpoint is reused as-is for the /api/v3/account endpoint. This might include unwanted parameters for the account endpoint which could cause the malformed URL error.

Before calling sendSignedRequest, you should clear or recreate the parameters map to make sure it contains only the necessary and relevant parameters for the account endpoint. In the provided correction, I used parameters.clear() to empty the map, ensuring that no incorrect or irrelevant parameters are sent in the request to the /api/v3/account endpoint.

This should resolve the issue of the malformed URL as it ensures that each endpoint receives only the parameters that are appropriate and expected.

1 Like

Yes, I change parameters for /api/v3/account endpoint:

parameters.insert({
		{"omitZeroBalances", "true"}}
  );

sendSignedRequest(curl, "GET", "/api/v3/account", parameters);

But error stay the same:

  • URL rejected: Malformed input to a URL function
  • Closing connection
    curl_easy_perform() failed: URL using bad/illegal format or missing URL
    , URL rejected: Malformed input to a URL function

I think for solve the issue I should URL encode signature.

Try the below example:

#include <curl/curl.h> // Include the CURL library for making HTTP requests
#include // Include map for handling parameters
#include // Standard C++ library for input and output

// Function to URL encode a string
std::string urlencode(const std::string &s) {
CURL *curl = curl_easy_init();
if(curl) {
char *output = curl_easy_escape(curl, s.c_str(), s.length());
if(output) {
std::string encoded(output); // Store the encoded string
curl_free(output); // Free the output string
curl_easy_cleanup(curl); // Clean up the CURL object
return encoded; // Return the encoded string
}
curl_easy_cleanup(curl); // Clean up the CURL object if encoding fails
}
return “”; // Return an empty string if CURL fails to initialize
}

// Function to send a public request using CURL
void sendPublicRequest(CURL *curl, const std::string &url, const std::map<std::string, std::string> &params) {
std::string query_string;
for (const auto &param : params) {
if (!query_string.empty()) query_string += “&”; // Separate parameters with &
// Append the encoded key and value to the query string
query_string += urlencode(param.first) + “=” + urlencode(param.second);
}

std::string full_url = url + "?" + query_string;  // Construct the full URL
curl_easy_setopt(curl, CURLOPT_URL, full_url.c_str());  // Set the URL for the CURL request
CURLcode res = curl_easy_perform(curl);  // Perform the CURL request

if (res != CURLE_OK) {
    std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
}

}

int main() {
CURL *curl = curl_easy_init(); // Initialize a CURL object
if(curl) {
std::map<std::string, std::string> parameters; // Map to store API parameters
parameters.insert({“symbol”, “BTCUSDT”});
parameters.insert({“interval”, “1d”});
parameters.insert({“limit”, “10”});

    // Send a public API request
    sendPublicRequest(curl, "https://api.binance.com/api/v3/klines", parameters);
    
    curl_easy_cleanup(curl);  // Clean up the CURL object
}
return 0;

}

Sorry a bit rusty in C++.

1 Like

After I added curl_easy_escape:

std::string getSignature(std::string query) {
        std::string signature = encryptWithEd25519(apiSecret.c_str(), query.c_str());
        std::unique_ptr<char, decltype(&curl_free)> urlEncodedSignatureUnqPtr{
            curl_easy_escape(curl, signature.c_str(), signature.length())
            , curl_free
        };
        std::string urlEncodedSignature(urlEncodedSignatureUnqPtr.get());
        return "&signature=" + urlEncodedSignature;
}

I’ve got an error:

< HTTP/2 400

  • Connection #0 to host api.binance.com left intact
    {
    “code” : -1022,
    “msg” : “Signature for this request is not valid.”
    }

Final URL is :

https://api.binance.com/api/v3/account?omitZeroBalances=true&timestamp=1725370200382&signature=vt5hWNQCpie5m%2BOwCu9Wxch3x1yipmD9s1dSu6aazTOqzbXEzOJLgDPM4E%2F4SVod 2I1%2BLEQ4aM0NTZUIf7RXDg%3D%3D

After I removing any newlines that would normally be inserted every 64 characters by OpenSSL base64 encoding, my version of https://github.com/binance/binance-signature-examples.git started to work fine:

std::string getSignature(std::string query) {
        std::string signature = encryptWithEd25519(apiSecret.c_str(), query.c_str());
        signature.erase(std::remove_if(signature.begin(), signature.end()
              , [](char c) {
                return c == '\n' || c == '\r';
              }
            )
            , signature.end()
        );
        return "&signature=" + signature;
}

@Asheesh_Kumar thanks for your help!