Merge pull request #3465 from libgit2/cmn/tls-register stream: allow registering a user-provided TLS constructor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b2e433..dec40e4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,11 +17,16 @@ v0.23 + 1
the opportunity for concurrent operations and not committing any
changes until the unlock.
+
* `git_diff_options` added a new callback `progress_cb` to report on the
progress of the diff as files are being compared. The documentation of
the existing callback `notify_cb` was updated to reflect that it only
gets called when new deltas are added to the diff.
+* `git_stream_register_tls()` lets you register a callback to be used
+ as the constructor for a TLS stream instead of the libgit2 built-in
+ one.
+
### API removals
### Breaking API changes
diff --git a/include/git2/sys/stream.h b/include/git2/sys/stream.h
index 55a714b..2b4ff7f 100644
--- a/include/git2/sys/stream.h
+++ b/include/git2/sys/stream.h
@@ -39,6 +39,19 @@ typedef struct git_stream {
void (*free)(struct git_stream *);
} git_stream;
+typedef int (*git_stream_cb)(git_stream **out, const char *host, const char *port);
+
+/**
+ * Register a TLS stream constructor for the library to use
+ *
+ * If a constructor is already set, it will be overwritten. Pass
+ * `NULL` in order to deregister the current constructor.
+ *
+ * @param ctor the constructor to use
+ * @return 0 or an error code
+ */
+GIT_EXTERN(int) git_stream_register_tls(git_stream_cb ctor);
+
GIT_END_DECL
#endif
diff --git a/src/stream.h b/src/stream.h
index 43fcc30..4692c71 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -62,6 +62,9 @@ GIT_INLINE(int) git_stream_close(git_stream *st)
GIT_INLINE(void) git_stream_free(git_stream *st)
{
+ if (!st)
+ return;
+
st->free(st);
}
diff --git a/src/tls_stream.c b/src/tls_stream.c
index 39a8ce3..83e2d06 100644
--- a/src/tls_stream.c
+++ b/src/tls_stream.c
@@ -11,8 +11,21 @@
#include "openssl_stream.h"
#include "stransport_stream.h"
+static git_stream_cb tls_ctor;
+
+int git_stream_register_tls(git_stream_cb ctor)
+{
+ tls_ctor = ctor;
+
+ return 0;
+}
+
int git_tls_stream_new(git_stream **out, const char *host, const char *port)
{
+
+ if (tls_ctor)
+ return tls_ctor(out, host, port);
+
#ifdef GIT_SECURE_TRANSPORT
return git_stransport_stream_new(out, host, port);
#elif defined(GIT_OPENSSL)
diff --git a/tests/core/stream.c b/tests/core/stream.c
new file mode 100644
index 0000000..ace6a05
--- /dev/null
+++ b/tests/core/stream.c
@@ -0,0 +1,47 @@
+#include "clar_libgit2.h"
+#include "git2/sys/stream.h"
+#include "tls_stream.h"
+#include "stream.h"
+
+static git_stream test_stream;
+static int ctor_called;
+
+static int test_ctor(git_stream **out, const char *host, const char *port)
+{
+ GIT_UNUSED(host);
+ GIT_UNUSED(port);
+
+ ctor_called = 1;
+ *out = &test_stream;
+
+ return 0;
+}
+
+void test_core_stream__register_tls(void)
+{
+ git_stream *stream;
+ int error;
+
+ ctor_called = 0;
+ cl_git_pass(git_stream_register_tls(test_ctor));
+ cl_git_pass(git_tls_stream_new(&stream, "localhost", "443"));
+ cl_assert_equal_i(1, ctor_called);
+ cl_assert_equal_p(&test_stream, stream);
+
+ ctor_called = 0;
+ stream = NULL;
+ cl_git_pass(git_stream_register_tls(NULL));
+ error = git_tls_stream_new(&stream, "localhost", "443");
+
+ /* We don't have arbitrary TLS stream support on Windows */
+#if GIT_WIN32
+ cl_git_fail_with(-1, error);
+#else
+ cl_git_pass(error);
+#endif
+
+ cl_assert_equal_i(0, ctor_called);
+ cl_assert(&test_stream != stream);
+
+ git_stream_free(stream);
+}