From 45c1741235a1fbd54484fa1c67ea68569dcfa23e Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 10 Sep 2007 23:02:28 -0400 Subject: Refactor http.h USE_CURL_MULTI fill_active_slots(). This removes all of the boilerplate and http-internal stuff from fill_active_slots() and makes it easy to turn into a callback. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- http.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'http.c') diff --git a/http.c b/http.c index c6fb8ace9f..1f305bd355 100644 --- a/http.c +++ b/http.c @@ -372,6 +372,7 @@ int start_active_slot(struct active_request_slot *slot) { #ifdef USE_CURL_MULTI CURLMcode curlm_result = curl_multi_add_handle(curlm, slot->curl); + int num_transfers; if (curlm_result != CURLM_OK && curlm_result != CURLM_CALL_MULTI_PERFORM) { @@ -379,11 +380,34 @@ int start_active_slot(struct active_request_slot *slot) slot->in_use = 0; return 0; } + + /* + * We know there must be something to do, since we just added + * something. + */ + curl_multi_perform(curlm, &num_transfers); #endif return 1; } #ifdef USE_CURL_MULTI +void fill_active_slots(void) +{ + struct active_request_slot *slot = active_queue_head; + + while (active_requests < max_requests) + if (!fill_active_slot()) + break; + + while (slot != NULL) { + if (!slot->in_use && slot->curl != NULL) { + curl_easy_cleanup(slot->curl); + slot->curl = NULL; + } + slot = slot->next; + } +} + void step_active_slots(void) { int num_transfers; -- cgit v1.2.3 From fc57b6aaa5bc59ecbe0c052b98196a93b35760a5 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Mon, 10 Sep 2007 23:02:34 -0400 Subject: Make function to refill http queue a callback This eliminates the last function provided by the code using http.h as a global symbol, so it should be possible to have multiple programs using http.h in the same executable, and it also adds an argument to that callback, so that info can be passed into the callback without being global. Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- http.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index 1f305bd355..a95483be8b 100644 --- a/http.c +++ b/http.c @@ -391,13 +391,39 @@ int start_active_slot(struct active_request_slot *slot) } #ifdef USE_CURL_MULTI +struct fill_chain { + void *data; + int (*fill)(void *); + struct fill_chain *next; +}; + +static struct fill_chain *fill_cfg = NULL; + +void add_fill_function(void *data, int (*fill)(void *)) +{ + struct fill_chain *new = malloc(sizeof(*new)); + struct fill_chain **linkp = &fill_cfg; + new->data = data; + new->fill = fill; + new->next = NULL; + while (*linkp) + linkp = &(*linkp)->next; + *linkp = new; +} + void fill_active_slots(void) { struct active_request_slot *slot = active_queue_head; - while (active_requests < max_requests) - if (!fill_active_slot()) + while (active_requests < max_requests) { + struct fill_chain *fill; + for (fill = fill_cfg; fill; fill = fill->next) + if (fill->fill(fill->data)) + break; + + if (!fill) break; + } while (slot != NULL) { if (!slot->in_use && slot->curl != NULL) { -- cgit v1.2.3 From 3278cd0a39c30c6c3082fc5feed0f9bd98b5f628 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 15 Sep 2007 03:23:00 -0400 Subject: Properly cleanup in http_cleanup so builtin-fetch does not segfault Junio and I both noticed that the new builtin-fetch was segfaulting immediately on http/https/ftp style URLs (those that went through libcurl and the commit walker). Although the builtin-fetch changes in this area were really just minor refactorings there was one major change made: we invoked http_init(), http_cleanup() then http_init() again in the same process. When we call curl_easy_cleanup() on each active_request_slot we are telling libcurl we did not want that buffer to be used again. Unfortunately we did not also deallocate the active_request_slot itself nor did we NULL out active_queue_head. This lead us to attempt to reuse these cleaned up libcurl handles when we later tried to invoke http_init() a second time to reactivate the curl library. The next file get operation then immediately segfaulted on most versions of libcurl. Properly freeing our own buffers and clearing the list causes us to reinitialize the curl buffers again if/when we need to use libcurl from within this same process. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- http.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index a95483be8b..87ebf7b865 100644 --- a/http.c +++ b/http.c @@ -276,6 +276,7 @@ void http_cleanup(void) #endif while (slot != NULL) { + struct active_request_slot *next = slot->next; #ifdef USE_CURL_MULTI if (slot->in_use) { curl_easy_getinfo(slot->curl, @@ -287,8 +288,10 @@ void http_cleanup(void) #endif if (slot->curl != NULL) curl_easy_cleanup(slot->curl); - slot = slot->next; + free(slot); + slot = next; } + active_queue_head = NULL; #ifndef NO_CURL_EASY_DUPHANDLE curl_easy_cleanup(curl_default); @@ -300,7 +303,7 @@ void http_cleanup(void) curl_global_cleanup(); curl_slist_free_all(pragma_header); - pragma_header = NULL; + pragma_header = NULL; } struct active_request_slot *get_active_slot(void) -- cgit v1.2.3 From 9c5665aa3c938b0e085ca34a8126110edcffa217 Mon Sep 17 00:00:00 2001 From: Sam Vilain Date: Fri, 23 Nov 2007 13:07:00 +1300 Subject: Allow HTTP proxy to be overridden in config The http_proxy / HTTPS_PROXY variables used by curl to control proxying may not be suitable for git. Allow the user to override them in the configuration file. Signed-off-by: Junio C Hamano --- http.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'http.c') diff --git a/http.c b/http.c index 87ebf7b865..e4aa9c19db 100644 --- a/http.c +++ b/http.c @@ -24,6 +24,7 @@ char *ssl_cainfo = NULL; long curl_low_speed_limit = -1; long curl_low_speed_time = -1; int curl_ftp_no_epsv = 0; +char *curl_http_proxy = NULL; struct curl_slist *pragma_header; @@ -160,6 +161,13 @@ static int http_options(const char *var, const char *value) curl_ftp_no_epsv = git_config_bool(var, value); return 0; } + if (!strcmp("http.proxy", var)) { + if (curl_http_proxy == NULL) { + curl_http_proxy = xmalloc(strlen(value)+1); + strcpy(curl_http_proxy, value); + } + return 0; + } /* Fall back on the default ones */ return git_default_config(var, value); @@ -205,6 +213,9 @@ static CURL* get_curl_handle(void) if (curl_ftp_no_epsv) curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0); + if (curl_http_proxy) + curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy); + return result; } -- cgit v1.2.3 From cc3530e8f3f512dd407f64caf2c9916cb26afbc2 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sun, 9 Dec 2007 18:04:57 +0100 Subject: Cleanup variables in http.[ch] Quite some variables defined as extern in http.h are only used in http.c, and some others, only defined in http.c, were not static. Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index e4aa9c19db..146f62609d 100644 --- a/http.c +++ b/http.c @@ -4,31 +4,31 @@ int data_received; int active_requests = 0; #ifdef USE_CURL_MULTI -int max_requests = -1; -CURLM *curlm; +static int max_requests = -1; +static CURLM *curlm; #endif #ifndef NO_CURL_EASY_DUPHANDLE -CURL *curl_default; +static CURL *curl_default; #endif char curl_errorstr[CURL_ERROR_SIZE]; -int curl_ssl_verify = -1; -char *ssl_cert = NULL; +static int curl_ssl_verify = -1; +static char *ssl_cert = NULL; #if LIBCURL_VERSION_NUM >= 0x070902 -char *ssl_key = NULL; +static char *ssl_key = NULL; #endif #if LIBCURL_VERSION_NUM >= 0x070908 -char *ssl_capath = NULL; +static char *ssl_capath = NULL; #endif -char *ssl_cainfo = NULL; -long curl_low_speed_limit = -1; -long curl_low_speed_time = -1; -int curl_ftp_no_epsv = 0; -char *curl_http_proxy = NULL; +static char *ssl_cainfo = NULL; +static long curl_low_speed_limit = -1; +static long curl_low_speed_time = -1; +static int curl_ftp_no_epsv = 0; +static char *curl_http_proxy = NULL; -struct curl_slist *pragma_header; +static struct curl_slist *pragma_header; -struct active_request_slot *active_queue_head = NULL; +static struct active_request_slot *active_queue_head = NULL; size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, struct buffer *buffer) -- cgit v1.2.3 From 02dc534fc6eb8a08c686b7cb2d979545853889d0 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 10 Dec 2007 22:36:08 +0100 Subject: Remove a CURLOPT_HTTPHEADER (un)setting Setting CURLOPT_HTTPHEADER doesn't add HTTP headers, but replaces whatever set of headers was configured before, so setting to NULL doesn't have any magic meaning, and is pretty much useless when setting to another list right after. Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http.c | 1 - 1 file changed, 1 deletion(-) (limited to 'http.c') diff --git a/http.c b/http.c index 146f62609d..ae57073a36 100644 --- a/http.c +++ b/http.c @@ -370,7 +370,6 @@ struct active_request_slot *get_active_slot(void) slot->finished = NULL; slot->callback_data = NULL; slot->callback_func = NULL; - curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL); curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header); curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr); curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL); -- cgit v1.2.3 From 028c2976389f70e7349bbfeeef0ed0a000d5e447 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Sun, 9 Dec 2007 20:30:59 +0100 Subject: Use strbuf in http code Also, replace whitespaces with tabs in some places Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index ae57073a36..dcc569343e 100644 --- a/http.c +++ b/http.c @@ -34,31 +34,25 @@ size_t fread_buffer(void *ptr, size_t eltsize, size_t nmemb, struct buffer *buffer) { size_t size = eltsize * nmemb; - if (size > buffer->size - buffer->posn) - size = buffer->size - buffer->posn; - memcpy(ptr, (char *) buffer->buffer + buffer->posn, size); + if (size > buffer->buf.len - buffer->posn) + size = buffer->buf.len - buffer->posn; + memcpy(ptr, buffer->buf.buf + buffer->posn, size); buffer->posn += size; + return size; } size_t fwrite_buffer(const void *ptr, size_t eltsize, - size_t nmemb, struct buffer *buffer) + size_t nmemb, struct strbuf *buffer) { size_t size = eltsize * nmemb; - if (size > buffer->size - buffer->posn) { - buffer->size = buffer->size * 3 / 2; - if (buffer->size < buffer->posn + size) - buffer->size = buffer->posn + size; - buffer->buffer = xrealloc(buffer->buffer, buffer->size); - } - memcpy((char *) buffer->buffer + buffer->posn, ptr, size); - buffer->posn += size; + strbuf_add(buffer, ptr, size); data_received++; return size; } size_t fwrite_null(const void *ptr, size_t eltsize, - size_t nmemb, struct buffer *buffer) + size_t nmemb, struct strbuf *buffer) { data_received++; return eltsize * nmemb; @@ -507,8 +501,8 @@ void run_active_slot(struct active_request_slot *slot) static void closedown_active_slot(struct active_request_slot *slot) { - active_requests--; - slot->in_use = 0; + active_requests--; + slot->in_use = 0; } void release_active_slot(struct active_request_slot *slot) @@ -529,7 +523,7 @@ void release_active_slot(struct active_request_slot *slot) static void finish_active_slot(struct active_request_slot *slot) { closedown_active_slot(slot); - curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); + curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); if (slot->finished != NULL) (*slot->finished) = 1; @@ -540,10 +534,10 @@ static void finish_active_slot(struct active_request_slot *slot) slot->results->http_code = slot->http_code; } - /* Run callback if appropriate */ - if (slot->callback_func != NULL) { - slot->callback_func(slot->callback_data); - } + /* Run callback if appropriate */ + if (slot->callback_func != NULL) { + slot->callback_func(slot->callback_data); + } } void finish_all_active_slots(void) -- cgit v1.2.3 From d7e92806cdc5ca78c4db879c68f91c70ff9e1ade Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 11 Dec 2007 00:08:25 +0100 Subject: Move fetch_ref from http-push.c and http-walker.c to http.c Make the necessary changes to be ok with their difference, and rename the function http_fetch_ref. Signed-off-by: Mike Hommey Signed-off-by: Junio C Hamano --- http.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'http.c') diff --git a/http.c b/http.c index dcc569343e..d2c11aee90 100644 --- a/http.c +++ b/http.c @@ -552,3 +552,85 @@ void finish_all_active_slots(void) slot = slot->next; } } + +static inline int needs_quote(int ch) +{ + if (((ch >= 'A') && (ch <= 'Z')) + || ((ch >= 'a') && (ch <= 'z')) + || ((ch >= '0') && (ch <= '9')) + || (ch == '/') + || (ch == '-') + || (ch == '.')) + return 0; + return 1; +} + +static inline int hex(int v) +{ + if (v < 10) return '0' + v; + else return 'A' + v - 10; +} + +static char *quote_ref_url(const char *base, const char *ref) +{ + const char *cp; + char *dp, *qref; + int len, baselen, ch; + + baselen = strlen(base); + len = baselen + 7; /* "/refs/" + NUL */ + for (cp = ref; (ch = *cp) != 0; cp++, len++) + if (needs_quote(ch)) + len += 2; /* extra two hex plus replacement % */ + qref = xmalloc(len); + memcpy(qref, base, baselen); + memcpy(qref + baselen, "/refs/", 6); + for (cp = ref, dp = qref + baselen + 6; (ch = *cp) != 0; cp++) { + if (needs_quote(ch)) { + *dp++ = '%'; + *dp++ = hex((ch >> 4) & 0xF); + *dp++ = hex(ch & 0xF); + } + else + *dp++ = ch; + } + *dp = 0; + + return qref; +} + +int http_fetch_ref(const char *base, const char *ref, unsigned char *sha1) +{ + char *url; + struct strbuf buffer = STRBUF_INIT; + struct active_request_slot *slot; + struct slot_results results; + int ret; + + url = quote_ref_url(base, ref); + slot = get_active_slot(); + slot->results = &results; + curl_easy_setopt(slot->curl, CURLOPT_FILE, &buffer); + curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer); + curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, NULL); + curl_easy_setopt(slot->curl, CURLOPT_URL, url); + if (start_active_slot(slot)) { + run_active_slot(slot); + if (results.curl_result == CURLE_OK) { + strbuf_rtrim(&buffer); + if (buffer.len == 40) + ret = get_sha1_hex(buffer.buf, sha1); + else + ret = 1; + } else { + ret = error("Couldn't get %s for %s\n%s", + url, ref, curl_errorstr); + } + } else { + ret = error("Unable to start request"); + } + + strbuf_release(&buffer); + free(url); + return ret; +} -- cgit v1.2.3 From 111dd25f3c34ccad101047c32e89d1bb87136f60 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 11 Feb 2008 10:57:22 -0800 Subject: http.c: guard config parser from value=NULL http.sslcert and friends expect a string value Signed-off-by: Junio C Hamano --- http.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'http.c') diff --git a/http.c b/http.c index d2c11aee90..5925d07478 100644 --- a/http.c +++ b/http.c @@ -101,16 +101,18 @@ static int http_options(const char *var, const char *value) if (!strcmp("http.sslcert", var)) { if (ssl_cert == NULL) { - ssl_cert = xmalloc(strlen(value)+1); - strcpy(ssl_cert, value); + if (!value) + return config_error_nonbool(var); + ssl_cert = xstrdup(value); } return 0; } #if LIBCURL_VERSION_NUM >= 0x070902 if (!strcmp("http.sslkey", var)) { if (ssl_key == NULL) { - ssl_key = xmalloc(strlen(value)+1); - strcpy(ssl_key, value); + if (!value) + return config_error_nonbool(var); + ssl_key = xstrdup(value); } return 0; } @@ -118,16 +120,18 @@ static int http_options(const char *var, const char *value) #if LIBCURL_VERSION_NUM >= 0x070908 if (!strcmp("http.sslcapath", var)) { if (ssl_capath == NULL) { - ssl_capath = xmalloc(strlen(value)+1); - strcpy(ssl_capath, value); + if (!value) + return config_error_nonbool(var); + ssl_capath = xstrdup(value); } return 0; } #endif if (!strcmp("http.sslcainfo", var)) { if (ssl_cainfo == NULL) { - ssl_cainfo = xmalloc(strlen(value)+1); - strcpy(ssl_cainfo, value); + if (!value) + return config_error_nonbool(var); + ssl_cainfo = xstrdup(value); } return 0; } @@ -157,8 +161,9 @@ static int http_options(const char *var, const char *value) } if (!strcmp("http.proxy", var)) { if (curl_http_proxy == NULL) { - curl_http_proxy = xmalloc(strlen(value)+1); - strcpy(curl_http_proxy, value); + if (!value) + return config_error_nonbool(var); + curl_http_proxy = xstrdup(value); } return 0; } -- cgit v1.2.3