16 RESULT_MULTI_INIT_FAIL
,
17 RESULT_EASY_INIT_FAIL
,
18 RESULT_SLIST_APPEND_FAIL
,
19 RESULT_NO_RUNNING_HANDLES
,
20 RESULT_MULTI_INFO_READ_FAIL
,
21 RESULT_UNKNOWN_MESSAGE
,
25 static const char *error_strings
[] =
30 "curl_multi_init() failed",
31 "curl_easy_init() failed",
32 "curl_slist_append() failed",
33 "curl_multi_perform() - no running handles",
34 "curl_multi_info_read() failed",
35 "curl_multi_info_read() returned unknown message",
43 struct curl_slist
*headers
;
47 static const char user_agent
[] =
48 "darcs/" PACKAGE_VERSION
" libcurl/" LIBCURL_VERSION
;
49 static const char *proxypass
;
50 static int init_done
= 0;
51 static CURLM
*multi
= NULL
;
52 static int msgs_in_queue
= 0;
53 static char *last_url
= NULL
;
55 static const char *perform()
58 int running_handles
, running_handles_last
;
59 fd_set fd_read
, fd_write
, fd_except
;
64 error
= curl_multi_perform(multi
, &running_handles
);
65 if (error
!= CURLM_OK
&& error
!= CURLM_CALL_MULTI_PERFORM
)
66 return curl_multi_strerror(error
);
67 if (running_handles
== 0)
68 return error_strings
[RESULT_NO_RUNNING_HANDLES
];
70 running_handles_last
= running_handles
;
73 while (error
== CURLM_CALL_MULTI_PERFORM
)
74 error
= curl_multi_perform(multi
, &running_handles
);
76 if (error
!= CURLM_OK
)
77 return curl_multi_strerror(error
);
79 if (running_handles
< running_handles_last
)
86 error
= curl_multi_fdset(multi
, &fd_read
, &fd_write
, &fd_except
, &max_fd
);
87 if (error
!= CURLM_OK
&& error
!= CURLM_CALL_MULTI_PERFORM
)
88 return curl_multi_strerror(error
);
90 #ifdef CURL_MULTI_TIMEOUT
91 error
= curl_multi_timeout(multi
, &timeout
);
92 if (error
!= CURLM_OK
&& error
!= CURLM_CALL_MULTI_PERFORM
)
93 return curl_multi_strerror(error
);
99 tval
.tv_sec
= timeout
/ 1000;
100 tval
.tv_usec
= timeout
% 1000 * 1000;
102 while (select(max_fd
+ 1, &fd_read
, &fd_write
, &fd_except
, &tval
) < 0)
106 perror(error_strings
[RESULT_SELECT_FAIL
]);
107 return error_strings
[RESULT_SELECT_FAIL
];
110 error
= CURLM_CALL_MULTI_PERFORM
;
116 const char *curl_request_url(const char *url
,
117 const char *filename
,
124 error
= curl_global_init(CURL_GLOBAL_ALL
);
125 if (error
!= CURLE_OK
)
126 return curl_easy_strerror(error
);
127 proxypass
= getenv("DARCS_PROXYUSERPWD");
133 multi
= curl_multi_init();
135 return error_strings
[RESULT_MULTI_INIT_FAIL
];
136 #ifdef CURL_PIPELINING
137 error
= curl_multi_setopt(multi
, CURLMOPT_PIPELINING
, 1);
138 if (error
!= CURLM_OK
&& error
!= CURLM_CALL_MULTI_PERFORM
)
139 return curl_multi_strerror(error
);
143 CURL
*easy
= curl_easy_init();
145 return error_strings
[RESULT_EASY_INIT_FAIL
];
149 error
= curl_easy_setopt(easy
, CURLOPT_VERBOSE
, 1);
150 if (error
!= CURLE_OK
)
151 return curl_easy_strerror(error
);
154 struct UrlData
*url_data
= malloc(sizeof(struct UrlData
));
155 if (url_data
== NULL
)
156 return error_strings
[RESULT_MALLOC_FAIL
];
158 url_data
->url
= strdup(url
);
159 if (url_data
->url
== NULL
)
160 return error_strings
[RESULT_MALLOC_FAIL
];
162 url_data
->file
= fopen(filename
,"wb");
163 if (url_data
->file
== NULL
)
166 perror(error_strings
[RESULT_FILE_OPEN_FAIL
]);
167 return error_strings
[RESULT_FILE_OPEN_FAIL
];
170 error
= curl_easy_setopt(easy
, CURLOPT_PRIVATE
, url_data
);
171 if (error
!= CURLE_OK
)
172 return curl_easy_strerror(error
);
174 error
= curl_easy_setopt(easy
, CURLOPT_URL
, url_data
->url
);
175 if (error
!= CURLE_OK
)
176 return curl_easy_strerror(error
);
178 #ifdef CURLOPT_WRITEDATA
179 error
= curl_easy_setopt(easy
, CURLOPT_WRITEDATA
, url_data
->file
);
181 error
= curl_easy_setopt(easy
, CURLOPT_FILE
, url_data
->file
);
183 if (error
!= CURLE_OK
)
184 return curl_easy_strerror(error
);
186 error
= curl_easy_setopt(easy
, CURLOPT_USERAGENT
, user_agent
);
187 if (error
!= CURLE_OK
)
188 return curl_easy_strerror(error
);
190 error
= curl_easy_setopt(easy
, CURLOPT_FOLLOWLOCATION
, 1);
191 if (error
!= CURLE_OK
)
192 return curl_easy_strerror(error
);
194 error
= curl_easy_setopt(easy
, CURLOPT_FAILONERROR
, 1);
195 if (error
!= CURLE_OK
)
196 return curl_easy_strerror(error
);
198 error
= curl_easy_setopt(easy
, CURLOPT_HTTPAUTH
, CURLAUTH_ANY
);
199 if (error
!= CURLE_OK
)
200 return curl_easy_strerror(error
);
202 /* libcurl currently always sends Pragma: no-cache, but never
203 Cache-Control, which is contradictory. We override both, just to
205 url_data
->headers
= curl_slist_append(NULL
, "Accept: */*");
209 curl_slist_append(url_data
->headers
, "Pragma: no-cache");
211 curl_slist_append(url_data
->headers
, "Cache-Control: no-cache");
213 else if(cache_time
> 0)
215 /* This won't work well with HTTP/1.0 proxies. */
217 snprintf(buf
, sizeof(buf
), "Cache-Control: max-age=%d", cache_time
);
218 buf
[sizeof(buf
) - 1] = '\n';
219 url_data
->headers
= curl_slist_append(url_data
->headers
, "Pragma:");
220 url_data
->headers
= curl_slist_append(url_data
->headers
, buf
);
224 url_data
->headers
= curl_slist_append(url_data
->headers
, "Pragma:");
225 url_data
->headers
= curl_slist_append(url_data
->headers
, "Cache-Control:");
227 if (url_data
->headers
== NULL
)
228 return error_strings
[RESULT_SLIST_APPEND_FAIL
];
230 error
= curl_easy_setopt(easy
, CURLOPT_HTTPHEADER
, url_data
->headers
);
231 if (error
!= CURLE_OK
)
232 return curl_easy_strerror(error
);
234 if (proxypass
&& *proxypass
)
236 error
= curl_easy_setopt(easy
, CURLOPT_PROXYUSERPWD
, proxypass
);
237 if (error
!= CURLE_OK
)
238 return curl_easy_strerror(error
);
241 error
= curl_multi_add_handle(multi
, easy
);
242 if (error
!= CURLM_OK
&& error
!= CURLM_CALL_MULTI_PERFORM
)
243 return curl_multi_strerror(error
);
245 return error_strings
[RESULT_OK
];
248 const char *curl_wait_next_url()
250 if (last_url
!= NULL
)
256 if (msgs_in_queue
== 0)
258 const char *error
= perform();
263 CURLMsg
*msg
= curl_multi_info_read(multi
, &msgs_in_queue
);
265 return error_strings
[RESULT_MULTI_INFO_READ_FAIL
];
267 if (msg
->msg
== CURLMSG_DONE
)
269 CURL
*easy
= msg
->easy_handle
;
270 CURLcode result
= msg
->data
.result
;
271 struct UrlData
*url_data
;
272 int error
= curl_easy_getinfo(easy
, CURLINFO_PRIVATE
, (char **)&url_data
);
273 if (error
!= CURLE_OK
)
274 return curl_easy_strerror(error
);
276 last_url
= url_data
->url
;
277 fclose(url_data
->file
);
278 curl_slist_free_all(url_data
->headers
);
281 error
= curl_multi_remove_handle(multi
, easy
);
282 if (error
!= CURLM_OK
&& error
!= CURLM_CALL_MULTI_PERFORM
)
283 return curl_multi_strerror(error
);
284 curl_easy_cleanup(easy
);
286 if (result
!= CURLE_OK
)
287 return curl_easy_strerror(result
);
290 return error_strings
[RESULT_UNKNOWN_MESSAGE
];
292 return error_strings
[RESULT_OK
];
295 const char *curl_last_url()
297 return last_url
!= NULL
? last_url
: "";
300 void curl_enable_debug()