Guest User

Curl HTTP pipeline mismatch repro

a guest
Apr 3rd, 2017
138
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <curl/curl.h>
  2.  
  3. typedef struct
  4. {
  5.     int requestId;
  6.     char response[1024];
  7.     size_t responseLen;
  8. } TestData;
  9.  
  10. static size_t write_callback(void *contents, size_t size, size_t nmemb, TestData *data)
  11. {
  12.   size_t realsize = size * nmemb;
  13.   if (data->responseLen + realsize > sizeof(data->response))
  14.       exit(1);
  15.  
  16.   memcpy(&data->response[data->responseLen], contents, realsize);
  17.   data->responseLen += realsize;
  18.  
  19.   return realsize;
  20. }
  21.  
  22. static int parseId(const char* d, size_t len)
  23. {
  24.     char* c = strstr(d, "\"id\":") + 7;
  25.     char* end = NULL;
  26.     return strtol(c, &end, 10);
  27. }
  28.  
  29. static void setup_handle(CURL *handle, CURLM *m, TestData* data, int id)
  30. {
  31.     data->requestId = id;
  32.     data->responseLen = 0;
  33.  
  34.     static const char* url = "http://httpbin.org/get?id=%d";
  35.     char urlbuf[256];
  36.     snprintf(urlbuf, sizeof(urlbuf), url, id);
  37.     curl_easy_setopt(handle, CURLOPT_URL, urlbuf);
  38.     curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
  39.     curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1L);
  40.     curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
  41.     curl_easy_setopt(handle, CURLOPT_WRITEDATA, data);
  42.     curl_easy_setopt(handle, CURLOPT_PRIVATE, data);
  43.     curl_multi_add_handle(m, handle);
  44. }
  45.  
  46. #define NUM_HANDLES 8
  47. #define NUM_REQUESTS 32
  48.  
  49. int main()
  50. {
  51.     CURLM *m = NULL;
  52.     CURL* reqs[NUM_HANDLES];
  53.     TestData data[NUM_HANDLES];
  54.     int reqId = 1;
  55.  
  56.     curl_global_init(CURL_GLOBAL_ALL);
  57.     m = curl_multi_init();
  58.     curl_multi_setopt(m, CURLMOPT_PIPELINING, 1L);
  59.     curl_multi_setopt(m, CURLMOPT_MAX_HOST_CONNECTIONS, 1L);
  60.     curl_multi_setopt(m, CURLMOPT_MAXCONNECTS, 1L);
  61.     curl_multi_setopt(m, CURLMOPT_MAX_PIPELINE_LENGTH, NUM_HANDLES);
  62.  
  63.     for (int i = 0; i < NUM_HANDLES; ++i)
  64.     {
  65.         reqs[i] = curl_easy_init();
  66.         setup_handle(reqs[i], m, &data[i], reqId++);
  67.     }
  68.  
  69.     for (;;)
  70.     {
  71.         int running;
  72.         int left;
  73.         CURLMsg *msg;
  74.         int action = 0;
  75.  
  76.         curl_multi_perform(m, &running);
  77.         if (!running)
  78.             break;
  79.      
  80.         while((msg = curl_multi_info_read(m, &left)))
  81.         {
  82.             action++;
  83.             if (msg->msg == CURLMSG_DONE)
  84.             {
  85.                 CURL* h = msg->easy_handle;
  86.                 TestData* d;
  87.                 curl_easy_getinfo(h, CURLINFO_PRIVATE, &d);
  88.                 int responseId = parseId(d->response, d->responseLen);
  89.                 if (responseId != d->requestId)
  90.                 {
  91.                     fprintf(stderr, "mismatch found: req %d, rsp %d\n", d->requestId, responseId);
  92.                     exit(1);
  93.                 }
  94.                
  95.                 curl_multi_remove_handle(m, h);
  96.  
  97.                 if (reqId < NUM_REQUESTS)
  98.                 {
  99.                     curl_easy_reset(h);
  100.                     setup_handle(h, m, d, reqId++);
  101.                 }
  102.             }
  103.         }
  104.  
  105.         if (!action)
  106.         {
  107.             curl_multi_wait(m, NULL, 0, 5000, NULL);
  108.         }
  109.     }
  110.  
  111.     return 0;
  112. }
RAW Paste Data