Commit 21142c5a by Edward Thomson

http: remove cURL

We previously used cURL to support HTTP proxies.  Now that we've added
this support natively, we can remove the curl dependency.
parent 2878ad08
......@@ -60,7 +60,6 @@ OPTION(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON)
OPTION(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF)
OPTION(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF)
OPTION(VALGRIND "Configure build for valgrind" OFF)
OPTION(CURL "Use curl for HTTP if available" ON)
OPTION(USE_EXT_HTTP_PARSER "Use system HTTP_Parser if available" ON)
OPTION(DEBUG_POOL "Enable debug pool allocator" OFF)
OPTION(ENABLE_WERROR "Enable compilation with -Werror" OFF)
......
......@@ -125,17 +125,6 @@ IF (WIN32 AND WINHTTP)
LIST(APPEND LIBGIT2_LIBS "rpcrt4" "crypt32" "ole32")
LIST(APPEND LIBGIT2_PC_LIBS "-lrpcrt4" "-lcrypt32" "-lole32")
ELSE ()
IF (CURL)
FIND_PKGLIBRARIES(CURL libcurl)
ENDIF ()
IF (CURL_FOUND)
SET(GIT_CURL 1)
LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${CURL_INCLUDE_DIRS})
LIST(APPEND LIBGIT2_LIBS ${CURL_LIBRARIES})
LIST(APPEND LIBGIT2_PC_LIBS ${CURL_LDFLAGS})
ENDIF()
ADD_FEATURE_INFO(cURL GIT_CURL "cURL for HTTP proxy support")
ENDIF()
IF (USE_HTTPS)
......
......@@ -22,7 +22,6 @@
#cmakedefine GIT_GSSAPI 1
#cmakedefine GIT_WINHTTP 1
#cmakedefine GIT_CURL 1
#cmakedefine GIT_HTTPS 1
#cmakedefine GIT_OPENSSL 1
......
......@@ -13,7 +13,6 @@
#include "filter.h"
#include "merge_driver.h"
#include "streams/tls.h"
#include "streams/curl.h"
#include "streams/mbedtls.h"
#include "streams/openssl.h"
#include "thread-utils.h"
......@@ -70,7 +69,6 @@ static int init_common(void)
(ret = git_transport_ssh_global_init()) == 0 &&
(ret = git_tls_stream_global_init()) == 0 &&
(ret = git_openssl_stream_global_init()) == 0 &&
(ret = git_curl_stream_global_init()) == 0 &&
(ret = git_mbedtls_stream_global_init()) == 0)
ret = git_mwindow_global_init();
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "streams/curl.h"
#ifdef GIT_CURL
#include <curl/curl.h>
#include "stream.h"
#include "git2/transport.h"
#include "buffer.h"
#include "global.h"
#include "vector.h"
#include "proxy.h"
/* This is for backwards compatibility with curl<7.45.0. */
#ifndef CURLINFO_ACTIVESOCKET
# define CURLINFO_ACTIVESOCKET CURLINFO_LASTSOCKET
# define GIT_CURL_BADSOCKET -1
# define git_activesocket_t long
#else
# define GIT_CURL_BADSOCKET CURL_SOCKET_BAD
# define git_activesocket_t curl_socket_t
#endif
typedef struct {
git_stream parent;
CURL *handle;
curl_socket_t socket;
char curl_error[CURL_ERROR_SIZE + 1];
git_cert_x509 cert_info;
git_strarray cert_info_strings;
git_proxy_options proxy;
git_cred *proxy_cred;
} curl_stream;
int git_curl_stream_global_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
giterr_set(GITERR_NET, "could not initialize curl");
return -1;
}
/* `curl_global_cleanup` is provided by libcurl */
git__on_shutdown(curl_global_cleanup);
return 0;
}
static int seterr_curl(curl_stream *s)
{
giterr_set(GITERR_NET, "curl error: %s\n", s->curl_error);
return -1;
}
GIT_INLINE(int) error_no_credentials(void)
{
giterr_set(GITERR_NET, "proxy authentication required, but no callback provided");
return GIT_EAUTH;
}
static int apply_proxy_creds(curl_stream *s)
{
CURLcode res;
git_cred_userpass_plaintext *userpass;
if (!s->proxy_cred)
return GIT_ENOTFOUND;
userpass = (git_cred_userpass_plaintext *) s->proxy_cred;
if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYUSERNAME, userpass->username)) != CURLE_OK)
return seterr_curl(s);
if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYPASSWORD, userpass->password)) != CURLE_OK)
return seterr_curl(s);
return 0;
}
static int ask_and_apply_proxy_creds(curl_stream *s)
{
int error;
git_proxy_options *opts = &s->proxy;
if (!opts->credentials)
return error_no_credentials();
/* TODO: see if PROXYAUTH_AVAIL helps us here */
git_cred_free(s->proxy_cred);
s->proxy_cred = NULL;
giterr_clear();
error = opts->credentials(&s->proxy_cred, opts->url, NULL, GIT_CREDTYPE_USERPASS_PLAINTEXT, opts->payload);
if (error == GIT_PASSTHROUGH)
return error_no_credentials();
if (error < 0) {
if (!giterr_last())
giterr_set(GITERR_NET, "proxy authentication was aborted by the user");
return error;
}
if (s->proxy_cred->credtype != GIT_CREDTYPE_USERPASS_PLAINTEXT) {
giterr_set(GITERR_NET, "credentials callback returned invalid credential type");
return -1;
}
return apply_proxy_creds(s);
}
static int curls_connect(git_stream *stream)
{
curl_stream *s = (curl_stream *) stream;
git_activesocket_t sockextr;
long connect_last = 0;
int failed_cert = 0, error;
bool retry_connect;
CURLcode res;
/* Apply any credentials we've already established */
error = apply_proxy_creds(s);
if (error < 0 && error != GIT_ENOTFOUND)
return seterr_curl(s);
do {
retry_connect = 0;
res = curl_easy_perform(s->handle);
curl_easy_getinfo(s->handle, CURLINFO_HTTP_CONNECTCODE, &connect_last);
/* HTTP 407 Proxy Authentication Required */
if (connect_last == 407) {
if ((error = ask_and_apply_proxy_creds(s)) < 0)
return error;
retry_connect = true;
}
} while (retry_connect);
if (res != CURLE_OK && res != CURLE_PEER_FAILED_VERIFICATION)
return seterr_curl(s);
if (res == CURLE_PEER_FAILED_VERIFICATION)
failed_cert = 1;
if ((res = curl_easy_getinfo(s->handle, CURLINFO_ACTIVESOCKET, &sockextr)) != CURLE_OK) {
return seterr_curl(s);
}
if (sockextr == GIT_CURL_BADSOCKET) {
giterr_set(GITERR_NET, "curl socket is no longer valid");
return -1;
}
s->socket = sockextr;
if (s->parent.encrypted && failed_cert)
return GIT_ECERTIFICATE;
return 0;
}
static int curls_certificate(git_cert **out, git_stream *stream)
{
int error;
CURLcode res;
struct curl_slist *slist;
struct curl_certinfo *certinfo;
git_vector strings = GIT_VECTOR_INIT;
curl_stream *s = (curl_stream *) stream;
if ((res = curl_easy_getinfo(s->handle, CURLINFO_CERTINFO, &certinfo)) != CURLE_OK)
return seterr_curl(s);
/* No information is available, can happen with SecureTransport */
if (certinfo->num_of_certs == 0) {
s->cert_info.parent.cert_type = GIT_CERT_NONE;
s->cert_info.data = NULL;
s->cert_info.len = 0;
return 0;
}
if ((error = git_vector_init(&strings, 8, NULL)) < 0)
return error;
for (slist = certinfo->certinfo[0]; slist; slist = slist->next) {
char *str = git__strdup(slist->data);
GITERR_CHECK_ALLOC(str);
git_vector_insert(&strings, str);
}
/* Copy the contents of the vector into a strarray so we can expose them */
s->cert_info_strings.strings = (char **) strings.contents;
s->cert_info_strings.count = strings.length;
s->cert_info.parent.cert_type = GIT_CERT_STRARRAY;
s->cert_info.data = &s->cert_info_strings;
s->cert_info.len = strings.length;
*out = &s->cert_info.parent;
return 0;
}
static int curls_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
{
int error;
CURLcode res;
curl_stream *s = (curl_stream *) stream;
git_proxy_options_clear(&s->proxy);
if ((error = git_proxy_options_dup(&s->proxy, proxy_opts)) < 0)
return error;
if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXY, s->proxy.url)) != CURLE_OK)
return seterr_curl(s);
if ((res = curl_easy_setopt(s->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY)) != CURLE_OK)
return seterr_curl(s);
return 0;
}
static int wait_for(curl_socket_t fd, bool reading)
{
int ret;
fd_set infd, outfd, errfd;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
assert(fd >= 0);
FD_SET(fd, &errfd);
if (reading)
FD_SET(fd, &infd);
else
FD_SET(fd, &outfd);
if ((ret = select(fd + 1, &infd, &outfd, &errfd, NULL)) < 0) {
giterr_set(GITERR_OS, "error in select");
return -1;
}
return 0;
}
static ssize_t curls_write(git_stream *stream, const char *data, size_t len, int flags)
{
int error;
size_t off = 0, sent;
CURLcode res;
curl_stream *s = (curl_stream *) stream;
GIT_UNUSED(flags);
do {
if ((error = wait_for(s->socket, false)) < 0)
return error;
res = curl_easy_send(s->handle, data + off, len - off, &sent);
if (res == CURLE_OK)
off += sent;
} while ((res == CURLE_OK || res == CURLE_AGAIN) && off < len);
if (res != CURLE_OK)
return seterr_curl(s);
return len;
}
static ssize_t curls_read(git_stream *stream, void *data, size_t len)
{
int error;
size_t read;
CURLcode res;
curl_stream *s = (curl_stream *) stream;
do {
if ((error = wait_for(s->socket, true)) < 0)
return error;
res = curl_easy_recv(s->handle, data, len, &read);
} while (res == CURLE_AGAIN);
if (res != CURLE_OK)
return seterr_curl(s);
return read;
}
static int curls_close(git_stream *stream)
{
curl_stream *s = (curl_stream *) stream;
if (!s->handle)
return 0;
curl_easy_cleanup(s->handle);
s->handle = NULL;
s->socket = 0;
return 0;
}
static void curls_free(git_stream *stream)
{
curl_stream *s = (curl_stream *) stream;
curls_close(stream);
git_strarray_free(&s->cert_info_strings);
git_proxy_options_clear(&s->proxy);
git_cred_free(s->proxy_cred);
git__free(s);
}
int git_curl_stream_new(git_stream **out, const char *host, const char *port)
{
curl_stream *st;
CURL *handle;
int iport = 0, error;
st = git__calloc(1, sizeof(curl_stream));
GITERR_CHECK_ALLOC(st);
handle = curl_easy_init();
if (handle == NULL) {
giterr_set(GITERR_NET, "failed to create curl handle");
git__free(st);
return -1;
}
if ((error = git__strntol32(&iport, port, strlen(port), NULL, 10)) < 0) {
git__free(st);
return error;
}
curl_easy_setopt(handle, CURLOPT_URL, host);
curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, st->curl_error);
curl_easy_setopt(handle, CURLOPT_PORT, iport);
curl_easy_setopt(handle, CURLOPT_CONNECT_ONLY, 1);
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 1);
curl_easy_setopt(handle, CURLOPT_CERTINFO, 1);
curl_easy_setopt(handle, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_easy_setopt(handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
/* curl_easy_setopt(handle, CURLOPT_VERBOSE, 1); */
st->parent.version = GIT_STREAM_VERSION;
st->parent.encrypted = 0; /* we don't encrypt ourselves */
st->parent.proxy_support = 1;
st->parent.connect = curls_connect;
st->parent.certificate = curls_certificate;
st->parent.set_proxy = curls_set_proxy;
st->parent.read = curls_read;
st->parent.write = curls_write;
st->parent.close = curls_close;
st->parent.free = curls_free;
st->handle = handle;
*out = (git_stream *) st;
return 0;
}
#else
#include "stream.h"
int git_curl_stream_global_init(void)
{
return 0;
}
int git_curl_stream_new(git_stream **out, const char *host, const char *port)
{
GIT_UNUSED(out);
GIT_UNUSED(host);
GIT_UNUSED(port);
giterr_set(GITERR_NET, "curl is not supported in this version");
return -1;
}
#endif
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_streams_curl_h__
#define INCLUDE_streams_curl_h__
#include "common.h"
#include "git2/sys/stream.h"
extern int git_curl_stream_global_init(void);
extern int git_curl_stream_new(git_stream **out, const char *host, const char *port);
#endif
......@@ -18,10 +18,6 @@
#include "git2/transport.h"
#include "util.h"
#ifdef GIT_CURL
# include "streams/curl.h"
#endif
#ifndef GIT_DEFAULT_CERT_LOCATION
#define GIT_DEFAULT_CERT_LOCATION NULL
#endif
......@@ -431,13 +427,7 @@ int git_mbedtls_stream_new(
assert(out && host && port);
#ifdef GIT_CURL
error = git_curl_stream_new(&stream, host, port);
#else
error = git_socket_stream_new(&stream, host, port);
#endif
if (error < 0)
if ((error = git_socket_stream_new(&stream, host, port)) < 0)
return error;
if ((error = mbedtls_stream_wrap(out, stream, host, 1)) < 0) {
......
......@@ -19,10 +19,6 @@
#include "git2/transport.h"
#include "git2/sys/openssl.h"
#ifdef GIT_CURL
# include "streams/curl.h"
#endif
#ifndef GIT_WIN32
# include <sys/types.h>
# include <sys/socket.h>
......@@ -752,13 +748,7 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
assert(out && host && port);
#ifdef GIT_CURL
error = git_curl_stream_new(&stream, host, port);
#else
error = git_socket_stream_new(&stream, host, port);
#endif
if (error < 0)
if ((error = git_socket_stream_new(&stream, host, port)) < 0)
return error;
if ((error = openssl_stream_wrap(out, stream, host, 1)) < 0) {
......
......@@ -16,7 +16,6 @@
#include "git2/transport.h"
#include "streams/socket.h"
#include "streams/curl.h"
static int stransport_error(OSStatus ret)
{
......@@ -308,11 +307,7 @@ int git_stransport_stream_new(git_stream **out, const char *host, const char *po
assert(out && host);
#ifdef GIT_CURL
error = git_curl_stream_new(&stream, host, port);
#else
error = git_socket_stream_new(&stream, host, port);
#endif
if (!error)
error = stransport_wrap(out, stream, host, 1);
......
......@@ -21,7 +21,6 @@
#include "auth_negotiate.h"
#include "streams/tls.h"
#include "streams/socket.h"
#include "streams/curl.h"
git_http_auth_scheme auth_schemes[] = {
{ GIT_AUTHTYPE_NEGOTIATE, "Negotiate", GIT_CREDTYPE_DEFAULT, git_http_auth_negotiate },
......@@ -653,17 +652,6 @@ static int write_chunk(git_stream *io, const char *buffer, size_t len)
return 0;
}
static int apply_proxy_config_to_stream(
git_stream *stream, git_proxy_options *proxy_opts)
{
/* Only set the proxy configuration on the curl stream. */
if (!git_stream_supports_proxy(stream) ||
proxy_opts->type == GIT_PROXY_NONE)
return 0;
return git_stream_set_proxy(stream, proxy_opts);
}
static int load_proxy_config(http_subtransport *t)
{
int error;
......@@ -954,21 +942,10 @@ static int http_connect(http_subtransport *t)
cb_payload = t->owner->message_cb_payload;
}
#ifdef GIT_CURL
if ((error = git_curl_stream_new(&stream,
t->server.url.host, t->server.url.port)) < 0)
goto on_error;
GITERR_CHECK_VERSION(stream, GIT_STREAM_VERSION, "git_stream");
if ((error = apply_proxy_config_to_stream(stream, &t->proxy_opts)) < 0)
goto on_error;
#else
if (url->use_ssl)
error = git_tls_stream_new(&stream, url->host, url->port);
else
error = git_socket_stream_new(&stream, url->host, url->port);
#endif
if (error < 0)
goto on_error;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment