Skip to content

Commit 7eb7edd

Browse files
authored
Merge pull request libgit2#6278 from lhchavez/git_transport_smart_remote_connect_options
transport: introduce `git_transport_smart_remote_connect_options`
2 parents d333dbe + cc4c37c commit 7eb7edd

File tree

5 files changed

+188
-3
lines changed

5 files changed

+188
-3
lines changed

include/git2/sys/remote.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#ifndef INCLUDE_sys_git_remote_h
99
#define INCLUDE_sys_git_remote_h
1010

11+
#include "git2/remote.h"
12+
1113
/**
1214
* @file git2/sys/remote.h
1315
* @brief Low-level remote functionality for custom transports
@@ -26,6 +28,19 @@ typedef enum {
2628
GIT_REMOTE_CAPABILITY_REACHABLE_OID = (1 << 1),
2729
} git_remote_capability_t;
2830

31+
/**
32+
* Disposes libgit2-initialized fields from a git_remote_connect_options.
33+
* This should only be used for git_remote_connect_options returned by
34+
* git_transport_remote_connect_options.
35+
*
36+
* Note that this does not free the `git_remote_connect_options` itself, just
37+
* the memory pointed to by it.
38+
*
39+
* @param opts The `git_remote_connect_options` struct to dispose.
40+
*/
41+
GIT_EXTERN(void) git_remote_connect_options_dispose(
42+
git_remote_connect_options *opts);
43+
2944
/** @} */
3045
GIT_END_DECL
3146
#endif

include/git2/sys/transport.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
#define INCLUDE_sys_git_transport_h
1010

1111
#include "git2/net.h"
12+
#include "git2/proxy.h"
1213
#include "git2/remote.h"
14+
#include "git2/strarray.h"
1315
#include "git2/transport.h"
1416
#include "git2/types.h"
15-
#include "git2/strarray.h"
16-
#include "git2/proxy.h"
1717

1818
/**
1919
* @file git2/sys/transport.h
@@ -261,6 +261,19 @@ GIT_EXTERN(int) git_transport_smart_certificate_check(git_transport *transport,
261261
*/
262262
GIT_EXTERN(int) git_transport_smart_credentials(git_credential **out, git_transport *transport, const char *user, int methods);
263263

264+
/**
265+
* Get a copy of the remote connect options
266+
*
267+
* All data is copied and must be freed by the caller by calling
268+
* `git_remote_connect_options_dispose`.
269+
*
270+
* @param out options struct to fill
271+
* @param transport the transport to extract the data from.
272+
*/
273+
GIT_EXTERN(int) git_transport_remote_connect_options(
274+
git_remote_connect_options *out,
275+
git_transport *transport);
276+
264277
/*
265278
*** End of base transport interface ***
266279
*** Begin interface for subtransports for the smart transport ***

src/libgit2/remote.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "git2/remote.h"
1313
#include "git2/transport.h"
14+
#include "git2/sys/remote.h"
1415
#include "git2/sys/transport.h"
1516

1617
#include "refspec.h"
@@ -53,7 +54,6 @@ int git_remote_connect_options_normalize(
5354
git_remote_connect_options *dst,
5455
git_repository *repo,
5556
const git_remote_connect_options *src);
56-
void git_remote_connect_options_dispose(git_remote_connect_options *opts);
5757

5858
int git_remote_capabilities(unsigned int *out, git_remote *remote);
5959

src/libgit2/transports/smart.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,18 @@ int git_transport_smart_credentials(git_credential **out, git_transport *transpo
425425
return connect_opts->callbacks.credentials(out, t->url, user, methods, connect_opts->callbacks.payload);
426426
}
427427

428+
int git_transport_remote_connect_options(
429+
git_remote_connect_options *out,
430+
git_transport *transport)
431+
{
432+
transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent);
433+
434+
GIT_ASSERT_ARG(out);
435+
GIT_ASSERT_ARG(transport);
436+
437+
return git_remote_connect_options_dup(out, &t->connect_opts);
438+
}
439+
428440
int git_transport_smart(git_transport **out, git_remote *owner, void *param)
429441
{
430442
transport_smart *t;

tests/libgit2/transport/register.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "clar_libgit2.h"
2+
#include "git2/sys/remote.h"
23
#include "git2/sys/transport.h"
34

5+
static const char *proxy_url = "https://proxy";
46
static git_transport _transport = GIT_TRANSPORT_INIT;
57

68
static int dummy_transport(git_transport **transport, git_remote *owner, void *param)
@@ -77,3 +79,146 @@ void test_transport_register__custom_transport_ssh(void)
7779
#endif
7880
}
7981
}
82+
83+
static int custom_subtransport_stream__read(
84+
git_smart_subtransport_stream *stream,
85+
char *buffer,
86+
size_t buf_size,
87+
size_t *bytes_read)
88+
{
89+
GIT_UNUSED(stream);
90+
GIT_UNUSED(buffer);
91+
GIT_UNUSED(buf_size);
92+
93+
*bytes_read = 0;
94+
95+
git_error_set_str(42, "unimplemented");
96+
return GIT_EUSER;
97+
}
98+
99+
static int custom_subtransport_stream__write(
100+
git_smart_subtransport_stream *stream,
101+
const char *buffer,
102+
size_t len)
103+
{
104+
GIT_UNUSED(stream);
105+
GIT_UNUSED(buffer);
106+
GIT_UNUSED(len);
107+
108+
git_error_set_str(42, "unimplemented");
109+
return GIT_EUSER;
110+
}
111+
112+
static void custom_subtransport_stream__free(
113+
git_smart_subtransport_stream *stream)
114+
{
115+
git__free(stream);
116+
}
117+
118+
struct custom_subtransport {
119+
git_smart_subtransport subtransport;
120+
git_transport *owner;
121+
int *called;
122+
};
123+
124+
static int custom_subtransport__action(
125+
git_smart_subtransport_stream **out,
126+
git_smart_subtransport *transport,
127+
const char *url,
128+
git_smart_service_t action)
129+
{
130+
struct custom_subtransport *t = (struct custom_subtransport *)transport;
131+
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
132+
int ret;
133+
134+
GIT_UNUSED(url);
135+
GIT_UNUSED(action);
136+
137+
ret = git_transport_remote_connect_options(&opts, t->owner);
138+
139+
/* increase the counter once if this function was called at all and once more if the URL matches. */
140+
(*t->called)++;
141+
if (strcmp(proxy_url, opts.proxy_opts.url) == 0)
142+
(*t->called)++;
143+
144+
git_remote_connect_options_dispose(&opts);
145+
146+
*out = git__calloc(1, sizeof(git_smart_subtransport_stream));
147+
(*out)->subtransport = transport;
148+
(*out)->read = custom_subtransport_stream__read;
149+
(*out)->write = custom_subtransport_stream__write;
150+
(*out)->free = custom_subtransport_stream__free;
151+
152+
return ret;
153+
}
154+
155+
static int custom_subtransport__close(git_smart_subtransport *transport)
156+
{
157+
GIT_UNUSED(transport);
158+
159+
return 0;
160+
}
161+
162+
static void custom_subtransport__free(git_smart_subtransport *transport)
163+
{
164+
GIT_UNUSED(transport);
165+
166+
git__free(transport);
167+
}
168+
169+
static int custom_transport_callback(git_smart_subtransport **out, git_transport *owner, void *param)
170+
{
171+
struct custom_subtransport *subtransport = git__calloc(1, sizeof(struct custom_subtransport));
172+
subtransport->called = (int *)param;
173+
subtransport->owner = owner;
174+
subtransport->subtransport.action = custom_subtransport__action;
175+
subtransport->subtransport.close = custom_subtransport__close;
176+
subtransport->subtransport.free = custom_subtransport__free;
177+
178+
*out = &subtransport->subtransport;
179+
180+
return 0;
181+
}
182+
183+
184+
static int custom_transport(git_transport **out, git_remote *owner, void *param)
185+
{
186+
struct git_smart_subtransport_definition definition;
187+
definition.callback = custom_transport_callback;
188+
definition.rpc = false;
189+
definition.param = param;
190+
return git_transport_smart(out, owner, &definition);
191+
}
192+
193+
void test_transport_register__custom_transport_callbacks(void)
194+
{
195+
git_transport *transport;
196+
int called = 0;
197+
const char *url = "custom://somepath";
198+
git_remote_connect_options opts = GIT_REMOTE_CONNECT_OPTIONS_INIT;
199+
git_repository *repo;
200+
git_remote *remote;
201+
202+
cl_git_pass(git_repository_init(&repo, "./transport", 0));
203+
cl_git_pass(git_remote_create(&remote, repo, "test",
204+
cl_fixture("testrepo.git")));
205+
206+
cl_git_pass(git_transport_register("custom", custom_transport, &called));
207+
208+
cl_git_pass(git_transport_new(&transport, remote, url));
209+
210+
opts.follow_redirects = GIT_REMOTE_REDIRECT_NONE;
211+
opts.proxy_opts.url = proxy_url;
212+
213+
/* This is expected to fail, since the subtransport_stream is not implemented */
214+
transport->connect(transport, url, GIT_SERVICE_UPLOADPACK_LS, &opts);
215+
/* the counter is increased twice if everything goes as planned */
216+
cl_assert_equal_i(2, called);
217+
cl_git_pass(transport->close(transport));
218+
transport->free(transport);
219+
220+
cl_git_pass(git_transport_unregister("custom"));
221+
git_remote_free(remote);
222+
git_repository_free(repo);
223+
cl_fixture_cleanup("testrepo.git");
224+
}

0 commit comments

Comments
 (0)