curl / Mailing Lists / curl-library / Single Mail
Buy commercial curl support from WolfSSL. We help you work out your issues, debug your libcurl applications, use the API, port to new platforms, add new features and more. With a team lead by the curl founder himself.

Missing data fragments when custom headers set

From: tangram67 via curl-library <curl-library_at_cool.haxx.se>
Date: Sun, 24 Nov 2019 10:21:07 +0100

Hi to all.

I'm using libcurl as a receiver for MP3 radio streams.
When using custom headers in conjunction with header and body data
callbacks, some data is missing in the data callbacks. This is also
reproducable when using the following command line:

curl --header "Icy-MetaData: 1" -sD - -o ./ndr1.mp3
http://ndr-edge-2061.dus-lg.cdn.addradio.net/ndr/ndr1niedersachsen/hannover/mp3/128/stream.mp3

If you play the resulting MP3 file with some kind of media player you
can hear dropdowns caused by missing data. If you remove the custom
header, then the stream is OK. Also this behaviour is independant of the
header value, so any header string will cause the problem.

You can also see the problem in the CURLOPT_WRITEFUNCTION callback.
Usually MP3 streams send around 1400 bytes per callback. When header(s)
are set, the byte count is smaller from time to time. But that is not
because the data is fragmented in more than one call, some data is
simply missing.

The following code is an excerpt of the cURL setup part of the C++ class
I'm using.
I hope this information helps...

Kind regards,
Dirk.

     // Set URL to download from
     errval = curl_easy_setopt(curl(), CURLOPT_URL, url.c_str());
     if (!success()) {
         throw util::app_error_fmt("TWebClient::execute() Setting URL
failed for $ [%]", url, errmsg());
     }

//    // Set custom headers (commented for now!)
//    if (!txHeaders.empty() && !util::assigned(headerList)) {
//        bool first = true;
//        headerList = nil;
//        for (size_t i=0; i<txHeaders.size(); ++i) {
//            const std::string& s = txHeaders.at(i);
//            struct curl_slist * sl = nil;
//            if (!s.empty()) {
//                if (first) {
//                    sl = headerList = curl_slist_append(NULL, s.c_str());
//                    first = false;
//                } else {
//                    sl = curl_slist_append(headerList, s.c_str());
//                }
//                if (!util::assigned(sl)) {
//                    throw util::app_error_fmt("TWebClient::execute()
Setting custom header failed for $ <%;> [%]", url, s, errmsg());
//                }
//            }
//        }
//        if (util::assigned(headerList)) {
//            errval = curl_easy_setopt(curl(), CURLOPT_HTTPHEADER,
headerList);
//            if (!success()) {
//                throw util::app_error_fmt("TWebClient::execute()
Setting custom headers failed for $ [%]", url, errmsg());
//            }
//        }
//    }

     // Setup transfer data callback
     if (nil != callback) {
         errval = curl_easy_setopt(curl(), CURLOPT_WRITEFUNCTION, callback);
         if (!success()) {
             throw util::app_error_fmt("TWebClient::execute() Setting
callback method failed for $ [%]", url, errmsg());
         }
     }
     errval = curl_easy_setopt(curl(), CURLOPT_WRITEDATA, this);
     if (!success()) {
         throw util::app_error_fmt("TWebClient::execute() Setting
CURLOPT_WRITEDATA option failed for $ [%]", url, errmsg());
     }

     // Setup header data callback
     if (requestHeaders && nil != onHeaderDataMethod) {
         errval = curl_easy_setopt(curl(), CURLOPT_HEADERFUNCTION,
writeHeaderDispatcher);
         if (!success()) {
             throw util::app_error_fmt("TWebClient::execute() Setting
header callback method failed for $ [%]", url, errmsg());
         }
         errval = curl_easy_setopt(curl(), CURLOPT_HEADERDATA, this);
         if (!success()) {
             throw util::app_error_fmt("TWebClient::execute() Setting
CURLOPT_HEADERDATA option failed for $ [%]", url, errmsg());
         }
     }

     // Enable all supported built-in compressions
     errval = curl_easy_setopt(curl(), CURLOPT_ACCEPT_ENCODING, "");
     if (!success()) {
         throw util::app_error_fmt("TWebClient::execute() Setting
CURLOPT_ACCEPT_ENCODING option failed for $ [%]", url, errmsg());
     }

     // Disable signal handlers
     errval = curl_easy_setopt(curl(), CURLOPT_NOSIGNAL, 1L);
     if (!success()) { // && CURLE_UNKNOWN_OPTION != errval) {
         throw util::app_error_fmt("TWebClient::execute() Setting
CURLOPT_NOSIGNAL option failed for $ [%]", url, errmsg());
     }

     // Set application user agent name
     errval = curl_easy_setopt(curl(), CURLOPT_USERAGENT, agent.c_str());
     if (!success()) {
         throw util::app_error_fmt("TWebClient::execute() Setting
CURLOPT_USERAGENT option failed for $", agent, errmsg());
     }

     // Be verbose?
     if (debug) {
         errval = curl_easy_setopt(curl(), CURLOPT_VERBOSE, 1L);
         if (!success()) {
             throw util::app_error_fmt("TWebClient::execute() Setting
CURLOPT_VERBOSE option failed for $", agent, errmsg());
         }
     }

     // Execute prepared CURL action...
     errval = curl_easy_perform(curl());
     return success();

-------------------------------------------------------------------
Unsubscribe: https://cool.haxx.se/list/listinfo/curl-library
Etiquette: https://curl.haxx.se/mail/etiquette.html
Received on 2019-11-24