|
Packit Service |
20376f |
/*
|
|
Packit Service |
20376f |
* Copyright (C) the libgit2 contributors. All rights reserved.
|
|
Packit Service |
20376f |
*
|
|
Packit Service |
20376f |
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
|
Packit Service |
20376f |
* a Linking Exception. For full terms see the included COPYING file.
|
|
Packit Service |
20376f |
*/
|
|
Packit Service |
20376f |
#include "git2.h"
|
|
Packit Service |
20376f |
#include "smart.h"
|
|
Packit Service |
20376f |
#include "refs.h"
|
|
Packit Service |
20376f |
#include "refspec.h"
|
|
Packit Service |
20376f |
#include "proxy.h"
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_smart__recv_cb(gitno_buffer *buf)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *) buf->cb_data;
|
|
Packit Service |
20376f |
size_t old_len, bytes_read;
|
|
Packit Service |
20376f |
int error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
assert(t->current_stream);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
old_len = buf->offset;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = t->current_stream->read(t->current_stream, buf->data + buf->offset, buf->len - buf->offset, &bytes_read)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
buf->offset += bytes_read;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (t->packetsize_cb && !t->cancelled.val) {
|
|
Packit Service |
20376f |
error = t->packetsize_cb(bytes_read, t->packetsize_payload);
|
|
Packit Service |
20376f |
if (error) {
|
|
Packit Service |
20376f |
git_atomic_set(&t->cancelled, 1);
|
|
Packit Service |
20376f |
return GIT_EUSER;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return (int)(buf->offset - old_len);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransport)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
if (t->current_stream) {
|
|
Packit Service |
20376f |
t->current_stream->free(t->current_stream);
|
|
Packit Service |
20376f |
t->current_stream = NULL;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (t->url) {
|
|
Packit Service |
20376f |
git__free(t->url);
|
|
Packit Service |
20376f |
t->url = NULL;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (close_subtransport &&
|
|
Packit Service |
20376f |
t->wrapped->close(t->wrapped) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_smart__set_callbacks(
|
|
Packit Service |
20376f |
git_transport *transport,
|
|
Packit Service |
20376f |
git_transport_message_cb progress_cb,
|
|
Packit Service |
20376f |
git_transport_message_cb error_cb,
|
|
Packit Service |
20376f |
git_transport_certificate_check_cb certificate_check_cb,
|
|
Packit Service |
20376f |
void *message_cb_payload)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
t->progress_cb = progress_cb;
|
|
Packit Service |
20376f |
t->error_cb = error_cb;
|
|
Packit Service |
20376f |
t->certificate_check_cb = certificate_check_cb;
|
|
Packit Service |
20376f |
t->message_cb_payload = message_cb_payload;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int http_header_name_length(const char *http_header)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
const char *colon = strchr(http_header, ':');
|
|
Packit Service |
20376f |
if (!colon)
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
return colon - http_header;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static bool is_malformed_http_header(const char *http_header)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
const char *c;
|
|
Packit Service |
20376f |
int name_len;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
// Disallow \r and \n
|
|
Packit Service |
20376f |
c = strchr(http_header, '\r');
|
|
Packit Service |
20376f |
if (c)
|
|
Packit Service |
20376f |
return true;
|
|
Packit Service |
20376f |
c = strchr(http_header, '\n');
|
|
Packit Service |
20376f |
if (c)
|
|
Packit Service |
20376f |
return true;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
// Require a header name followed by :
|
|
Packit Service |
20376f |
name_len = http_header_name_length(http_header);
|
|
Packit Service |
20376f |
if (name_len < 1)
|
|
Packit Service |
20376f |
return true;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return false;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static char *forbidden_custom_headers[] = {
|
|
Packit Service |
20376f |
"User-Agent",
|
|
Packit Service |
20376f |
"Host",
|
|
Packit Service |
20376f |
"Accept",
|
|
Packit Service |
20376f |
"Content-Type",
|
|
Packit Service |
20376f |
"Transfer-Encoding",
|
|
Packit Service |
20376f |
"Content-Length",
|
|
Packit Service |
20376f |
};
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static bool is_forbidden_custom_header(const char *custom_header)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
unsigned long i;
|
|
Packit Service |
20376f |
int name_len = http_header_name_length(custom_header);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
// Disallow headers that we set
|
|
Packit Service |
20376f |
for (i = 0; i < ARRAY_SIZE(forbidden_custom_headers); i++)
|
|
Packit Service |
20376f |
if (strncmp(forbidden_custom_headers[i], custom_header, name_len) == 0)
|
|
Packit Service |
20376f |
return true;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return false;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_smart__set_custom_headers(
|
|
Packit Service |
20376f |
git_transport *transport,
|
|
Packit Service |
20376f |
const git_strarray *custom_headers)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
size_t i;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (t->custom_headers.count)
|
|
Packit Service |
20376f |
git_strarray_free(&t->custom_headers);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!custom_headers)
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
for (i = 0; i < custom_headers->count; i++) {
|
|
Packit Service |
20376f |
if (is_malformed_http_header(custom_headers->strings[i])) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_INVALID, "custom HTTP header '%s' is malformed", custom_headers->strings[i]);
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
if (is_forbidden_custom_header(custom_headers->strings[i])) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_INVALID, "custom HTTP header '%s' is already set by libgit2", custom_headers->strings[i]);
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return git_strarray_copy(&t->custom_headers, custom_headers);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_smart__update_heads(transport_smart *t, git_vector *symrefs)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
size_t i;
|
|
Packit Service |
20376f |
git_pkt *pkt;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_clear(&t->heads);
|
|
Packit Service |
20376f |
git_vector_foreach(&t->refs, i, pkt) {
|
|
Packit Service |
20376f |
git_pkt_ref *ref = (git_pkt_ref *) pkt;
|
|
Packit Service |
20376f |
if (pkt->type != GIT_PKT_REF)
|
|
Packit Service |
20376f |
continue;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (symrefs) {
|
|
Packit Service |
20376f |
git_refspec *spec;
|
|
Packit Service |
20376f |
git_buf buf = GIT_BUF_INIT;
|
|
Packit Service |
20376f |
size_t j;
|
|
Packit Service |
20376f |
int error = 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_foreach(symrefs, j, spec) {
|
|
Packit Service |
20376f |
git_buf_clear(&buf;;
|
|
Packit Service |
20376f |
if (git_refspec_src_matches(spec, ref->head.name) &&
|
|
Packit Service |
20376f |
!(error = git_refspec_transform(&buf, spec, ref->head.name)))
|
|
Packit Service |
20376f |
ref->head.symref_target = git_buf_detach(&buf;;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_buf_free(&buf;;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (error < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (git_vector_insert(&t->heads, &ref->head) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static void free_symrefs(git_vector *symrefs)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
git_refspec *spec;
|
|
Packit Service |
20376f |
size_t i;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_foreach(symrefs, i, spec) {
|
|
Packit Service |
20376f |
git_refspec__free(spec);
|
|
Packit Service |
20376f |
git__free(spec);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_free(symrefs);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_smart__connect(
|
|
Packit Service |
20376f |
git_transport *transport,
|
|
Packit Service |
20376f |
const char *url,
|
|
Packit Service |
20376f |
git_cred_acquire_cb cred_acquire_cb,
|
|
Packit Service |
20376f |
void *cred_acquire_payload,
|
|
Packit Service |
20376f |
const git_proxy_options *proxy,
|
|
Packit Service |
20376f |
int direction,
|
|
Packit Service |
20376f |
int flags)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
git_smart_subtransport_stream *stream;
|
|
Packit Service |
20376f |
int error;
|
|
Packit Service |
20376f |
git_pkt *pkt;
|
|
Packit Service |
20376f |
git_pkt_ref *first;
|
|
Packit Service |
20376f |
git_vector symrefs;
|
|
Packit Service |
20376f |
git_smart_service_t service;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (git_smart__reset_stream(t, true) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
t->url = git__strdup(url);
|
|
Packit Service |
20376f |
GITERR_CHECK_ALLOC(t->url);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (git_proxy_options_dup(&t->proxy, proxy) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
t->direction = direction;
|
|
Packit Service |
20376f |
t->flags = flags;
|
|
Packit Service |
20376f |
t->cred_acquire_cb = cred_acquire_cb;
|
|
Packit Service |
20376f |
t->cred_acquire_payload = cred_acquire_payload;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (GIT_DIRECTION_FETCH == t->direction)
|
|
Packit Service |
20376f |
service = GIT_SERVICE_UPLOADPACK_LS;
|
|
Packit Service |
20376f |
else if (GIT_DIRECTION_PUSH == t->direction)
|
|
Packit Service |
20376f |
service = GIT_SERVICE_RECEIVEPACK_LS;
|
|
Packit Service |
20376f |
else {
|
|
Packit Service |
20376f |
giterr_set(GITERR_NET, "invalid direction");
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = t->wrapped->action(&stream, t->wrapped, t->url, service)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* Save off the current stream (i.e. socket) that we are working with */
|
|
Packit Service |
20376f |
t->current_stream = stream;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* 2 flushes for RPC; 1 for stateful */
|
|
Packit Service |
20376f |
if ((error = git_smart__store_refs(t, t->rpc ? 2 : 1)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* Strip the comment packet for RPC */
|
|
Packit Service |
20376f |
if (t->rpc) {
|
|
Packit Service |
20376f |
pkt = (git_pkt *)git_vector_get(&t->refs, 0);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!pkt || GIT_PKT_COMMENT != pkt->type) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_NET, "invalid response");
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
} else {
|
|
Packit Service |
20376f |
/* Remove the comment pkt from the list */
|
|
Packit Service |
20376f |
git_vector_remove(&t->refs, 0);
|
|
Packit Service |
20376f |
git__free(pkt);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* We now have loaded the refs. */
|
|
Packit Service |
20376f |
t->have_refs = 1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
first = (git_pkt_ref *)git_vector_get(&t->refs, 0);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = git_vector_init(&symrefs, 1, NULL)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* Detect capabilities */
|
|
Packit Service |
20376f |
if (git_smart__detect_caps(first, &t->caps, &symrefs) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* If the only ref in the list is capabilities^{} with OID_ZERO, remove it */
|
|
Packit Service |
20376f |
if (1 == t->refs.length && !strcmp(first->head.name, "capabilities^{}") &&
|
|
Packit Service |
20376f |
git_oid_iszero(&first->head.oid)) {
|
|
Packit Service |
20376f |
git_vector_clear(&t->refs);
|
|
Packit Service |
20376f |
git_pkt_free((git_pkt *)first);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* Keep a list of heads for _ls */
|
|
Packit Service |
20376f |
git_smart__update_heads(t, &symrefs);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
free_symrefs(&symrefs);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (t->rpc && git_smart__reset_stream(t, false) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* We're now logically connected. */
|
|
Packit Service |
20376f |
t->connected = 1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!t->have_refs) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_NET, "the transport has not yet loaded the refs");
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
*out = (const git_remote_head **) t->heads.contents;
|
|
Packit Service |
20376f |
*size = t->heads.length;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_smart__negotiation_step(git_transport *transport, void *data, size_t len)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
git_smart_subtransport_stream *stream;
|
|
Packit Service |
20376f |
int error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (t->rpc && git_smart__reset_stream(t, false) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (GIT_DIRECTION_FETCH != t->direction) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_NET, "this operation is only valid for fetch");
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = t->wrapped->action(&stream, t->wrapped, t->url, GIT_SERVICE_UPLOADPACK)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* If this is a stateful implementation, the stream we get back should be the same */
|
|
Packit Service |
20376f |
assert(t->rpc || t->current_stream == stream);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* Save off the current stream (i.e. socket) that we are working with */
|
|
Packit Service |
20376f |
t->current_stream = stream;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = stream->write(stream, (const char *)data, len)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream **stream)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
int error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (t->rpc && git_smart__reset_stream(t, false) < 0)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (GIT_DIRECTION_PUSH != t->direction) {
|
|
Packit Service |
20376f |
giterr_set(GITERR_NET, "this operation is only valid for push");
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if ((error = t->wrapped->action(stream, t->wrapped, t->url, GIT_SERVICE_RECEIVEPACK)) < 0)
|
|
Packit Service |
20376f |
return error;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* If this is a stateful implementation, the stream we get back should be the same */
|
|
Packit Service |
20376f |
assert(t->rpc || t->current_stream == *stream);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* Save off the current stream (i.e. socket) that we are working with */
|
|
Packit Service |
20376f |
t->current_stream = *stream;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static void git_smart__cancel(git_transport *transport)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_atomic_set(&t->cancelled, 1);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_smart__is_connected(git_transport *transport)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return t->connected;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_smart__read_flags(git_transport *transport, int *flags)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
*flags = t->flags;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int git_smart__close(git_transport *transport)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
git_vector *common = &t->common;
|
|
Packit Service |
20376f |
unsigned int i;
|
|
Packit Service |
20376f |
git_pkt *p;
|
|
Packit Service |
20376f |
int ret;
|
|
Packit Service |
20376f |
git_smart_subtransport_stream *stream;
|
|
Packit Service |
20376f |
const char flush[] = "0000";
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/*
|
|
Packit Service |
20376f |
* If we're still connected at this point and not using RPC,
|
|
Packit Service |
20376f |
* we should say goodbye by sending a flush, or git-daemon
|
|
Packit Service |
20376f |
* will complain that we disconnected unexpectedly.
|
|
Packit Service |
20376f |
*/
|
|
Packit Service |
20376f |
if (t->connected && !t->rpc &&
|
|
Packit Service |
20376f |
!t->wrapped->action(&stream, t->wrapped, t->url, GIT_SERVICE_UPLOADPACK)) {
|
|
Packit Service |
20376f |
t->current_stream->write(t->current_stream, flush, 4);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
ret = git_smart__reset_stream(t, true);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_foreach(common, i, p)
|
|
Packit Service |
20376f |
git_pkt_free(p);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_free(common);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (t->url) {
|
|
Packit Service |
20376f |
git__free(t->url);
|
|
Packit Service |
20376f |
t->url = NULL;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
t->connected = 0;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return ret;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static void git_smart__free(git_transport *transport)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
git_vector *refs = &t->refs;
|
|
Packit Service |
20376f |
unsigned int i;
|
|
Packit Service |
20376f |
git_pkt *p;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* Make sure that the current stream is closed, if we have one. */
|
|
Packit Service |
20376f |
git_smart__close(transport);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
/* Free the subtransport */
|
|
Packit Service |
20376f |
t->wrapped->free(t->wrapped);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_free(&t->heads);
|
|
Packit Service |
20376f |
git_vector_foreach(refs, i, p)
|
|
Packit Service |
20376f |
git_pkt_free(p);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_vector_free(refs);
|
|
Packit Service |
20376f |
git__free((char *)t->proxy.url);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git_strarray_free(&t->custom_headers);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
git__free(t);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
static int ref_name_cmp(const void *a, const void *b)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
const git_pkt_ref *ref_a = a, *ref_b = b;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return strcmp(ref_a->head.name, ref_b->head.name);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_transport_smart_certificate_check(git_transport *transport, git_cert *cert, int valid, const char *hostname)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return t->certificate_check_cb(cert, valid, hostname, t->message_cb_payload);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_transport_smart_credentials(git_cred **out, git_transport *transport, const char *user, int methods)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *)transport;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
return t->cred_acquire_cb(out, t->url, user, methods, t->cred_acquire_payload);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t = (transport_smart *) transport;
|
|
Packit Service |
20376f |
return git_proxy_options_dup(out, &t->proxy);
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
int git_transport_smart(git_transport **out, git_remote *owner, void *param)
|
|
Packit Service |
20376f |
{
|
|
Packit Service |
20376f |
transport_smart *t;
|
|
Packit Service |
20376f |
git_smart_subtransport_definition *definition = (git_smart_subtransport_definition *)param;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (!param)
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
t = git__calloc(1, sizeof(transport_smart));
|
|
Packit Service |
20376f |
GITERR_CHECK_ALLOC(t);
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
t->parent.version = GIT_TRANSPORT_VERSION;
|
|
Packit Service |
20376f |
t->parent.set_callbacks = git_smart__set_callbacks;
|
|
Packit Service |
20376f |
t->parent.set_custom_headers = git_smart__set_custom_headers;
|
|
Packit Service |
20376f |
t->parent.connect = git_smart__connect;
|
|
Packit Service |
20376f |
t->parent.close = git_smart__close;
|
|
Packit Service |
20376f |
t->parent.free = git_smart__free;
|
|
Packit Service |
20376f |
t->parent.negotiate_fetch = git_smart__negotiate_fetch;
|
|
Packit Service |
20376f |
t->parent.download_pack = git_smart__download_pack;
|
|
Packit Service |
20376f |
t->parent.push = git_smart__push;
|
|
Packit Service |
20376f |
t->parent.ls = git_smart__ls;
|
|
Packit Service |
20376f |
t->parent.is_connected = git_smart__is_connected;
|
|
Packit Service |
20376f |
t->parent.read_flags = git_smart__read_flags;
|
|
Packit Service |
20376f |
t->parent.cancel = git_smart__cancel;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
t->owner = owner;
|
|
Packit Service |
20376f |
t->rpc = definition->rpc;
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0) {
|
|
Packit Service |
20376f |
git__free(t);
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (git_vector_init(&t->heads, 16, ref_name_cmp) < 0) {
|
|
Packit Service |
20376f |
git__free(t);
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
if (definition->callback(&t->wrapped, &t->parent, definition->param) < 0) {
|
|
Packit Service |
20376f |
git__free(t);
|
|
Packit Service |
20376f |
return -1;
|
|
Packit Service |
20376f |
}
|
|
Packit Service |
20376f |
|
|
Packit Service |
20376f |
*out = (git_transport *) t;
|
|
Packit Service |
20376f |
return 0;
|
|
Packit Service |
20376f |
}
|