Commit 66024c7c by Carlos Martín Nieto

http: add https support when GnuTLS is available

If it's not available, an error saying so will be returned when trying
to use a https:// URL.

This also unifies a lot of the network code to use git_transport in
many places instead of an socket descriptor.
parent ad5df35a
...@@ -26,6 +26,7 @@ INCLUDE_DIRECTORIES(src include deps/http-parser) ...@@ -26,6 +26,7 @@ INCLUDE_DIRECTORIES(src include deps/http-parser)
FILE(GLOB SRC_HTTP deps/http-parser/*.c) FILE(GLOB SRC_HTTP deps/http-parser/*.c)
FIND_PACKAGE(GnuTLS)
IF (NOT WIN32) IF (NOT WIN32)
FIND_PACKAGE(ZLIB) FIND_PACKAGE(ZLIB)
ELSE() ELSE()
...@@ -86,6 +87,12 @@ IF (NOT CMAKE_BUILD_TYPE) ...@@ -86,6 +87,12 @@ IF (NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
ENDIF () ENDIF ()
IF (GNUTLS_FOUND)
INCLUDE_DIRECTORIES(GNUTLS_INCLUDE_DIR)
ADD_DEFINITIONS(-DGIT_GNUTLS)
ENDIF()
IF (THREADSAFE) IF (THREADSAFE)
IF (NOT WIN32) IF (NOT WIN32)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
...@@ -118,7 +125,7 @@ ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") ...@@ -118,7 +125,7 @@ ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
TARGET_LINK_LIBRARIES(git2 socket nsl) TARGET_LINK_LIBRARIES(git2 socket nsl)
ENDIF () ENDIF ()
TARGET_LINK_LIBRARIES(git2 ${CMAKE_THREAD_LIBS_INIT}) TARGET_LINK_LIBRARIES(git2 ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES})
SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING}) SET_TARGET_PROPERTIES(git2 PROPERTIES VERSION ${LIBGIT2_VERSION_STRING})
SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_VERSION_MAJOR}) SET_TARGET_PROPERTIES(git2 PROPERTIES SOVERSION ${LIBGIT2_VERSION_MAJOR})
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libgit2.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libgit2.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc @ONLY)
...@@ -154,7 +161,7 @@ IF (BUILD_CLAR) ...@@ -154,7 +161,7 @@ IF (BUILD_CLAR)
WORKING_DIRECTORY ${CLAR_PATH} WORKING_DIRECTORY ${CLAR_PATH}
) )
ADD_EXECUTABLE(libgit2_clar ${SRC} ${CLAR_PATH}/clar_main.c ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX}) ADD_EXECUTABLE(libgit2_clar ${SRC} ${CLAR_PATH}/clar_main.c ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX})
TARGET_LINK_LIBRARIES(libgit2_clar ${CMAKE_THREAD_LIBS_INIT}) TARGET_LINK_LIBRARIES(libgit2_clar ${CMAKE_THREAD_LIBS_INIT} ${GNUTLS_LIBRARIES})
IF (WIN32) IF (WIN32)
TARGET_LINK_LIBRARIES(libgit2_clar ws2_32) TARGET_LINK_LIBRARIES(libgit2_clar ws2_32)
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef GIT_GNUTLS
# include <gnutls/gnutls.h>
#endif
#ifdef GIT_WIN32 #ifdef GIT_WIN32
# include <io.h> # include <io.h>
...@@ -65,6 +69,12 @@ void giterr_clear(void); ...@@ -65,6 +69,12 @@ void giterr_clear(void);
void giterr_set_str(int error_class, const char *string); void giterr_set_str(int error_class, const char *string);
void giterr_set_regex(const regex_t *regex, int error_code); void giterr_set_regex(const regex_t *regex, int error_code);
#ifdef GIT_GNUTLS
typedef struct gitno_ssl {
gnutls_session_t session;
gnutls_certificate_credentials_t cred;
} gitno_ssl;
#endif
#include "util.h" #include "util.h"
......
...@@ -110,7 +110,7 @@ int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_st ...@@ -110,7 +110,7 @@ int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_st
int git_fetch__download_pack( int git_fetch__download_pack(
const char *buffered, const char *buffered,
size_t buffered_size, size_t buffered_size,
GIT_SOCKET fd, git_transport *t,
git_repository *repo, git_repository *repo,
git_off_t *bytes, git_off_t *bytes,
git_indexer_stats *stats) git_indexer_stats *stats)
...@@ -120,7 +120,7 @@ int git_fetch__download_pack( ...@@ -120,7 +120,7 @@ int git_fetch__download_pack(
gitno_buffer buf; gitno_buffer buf;
git_indexer_stream *idx; git_indexer_stream *idx;
gitno_buffer_setup(&buf, buff, sizeof(buff), fd); gitno_buffer_setup(t, &buf, buff, sizeof(buff));
if (memcmp(buffered, "PACK", strlen("PACK"))) { if (memcmp(buffered, "PACK", strlen("PACK"))) {
giterr_set(GITERR_NET, "The pack doesn't start with the signature"); giterr_set(GITERR_NET, "The pack doesn't start with the signature");
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
int git_fetch_negotiate(git_remote *remote); int git_fetch_negotiate(git_remote *remote);
int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats); int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats);
int git_fetch__download_pack(const char *buffered, size_t buffered_size, GIT_SOCKET fd, int git_fetch__download_pack(const char *buffered, size_t buffered_size, git_transport *t,
git_repository *repo, git_off_t *bytes, git_indexer_stats *stats); git_repository *repo, git_off_t *bytes, git_indexer_stats *stats);
int git_fetch_setup_walk(git_revwalk **out, git_repository *repo); int git_fetch_setup_walk(git_revwalk **out, git_repository *repo);
......
...@@ -18,6 +18,11 @@ ...@@ -18,6 +18,11 @@
# endif # endif
#endif #endif
#ifdef GIT_GNUTLS
# include <gnutls/openssl.h>
# include <gnutls/gnutls.h>
# include <gnutls/x509.h>
#endif
#include "git2/errors.h" #include "git2/errors.h"
...@@ -25,6 +30,7 @@ ...@@ -25,6 +30,7 @@
#include "netops.h" #include "netops.h"
#include "posix.h" #include "posix.h"
#include "buffer.h" #include "buffer.h"
#include "transport.h"
#ifdef GIT_WIN32 #ifdef GIT_WIN32
static void net_set_error(const char *str) static void net_set_error(const char *str)
...@@ -45,25 +51,66 @@ static void net_set_error(const char *str) ...@@ -45,25 +51,66 @@ static void net_set_error(const char *str)
} }
#endif #endif
void gitno_buffer_setup(gitno_buffer *buf, char *data, unsigned int len, GIT_SOCKET fd) #ifdef GIT_GNUTLS
static int ssl_set_error(int error)
{
giterr_set(GITERR_NET, "SSL error: (%s) %s", gnutls_strerror_name(error), gnutls_strerror(error));
return -1;
}
#endif
void gitno_buffer_setup(git_transport *t, gitno_buffer *buf, char *data, unsigned int len)
{ {
memset(buf, 0x0, sizeof(gitno_buffer)); memset(buf, 0x0, sizeof(gitno_buffer));
memset(data, 0x0, len); memset(data, 0x0, len);
buf->data = data; buf->data = data;
buf->len = len; buf->len = len;
buf->offset = 0; buf->offset = 0;
buf->fd = fd; buf->fd = t->socket;
#ifdef GIT__GNUTLS
if (t->encrypt)
buf->ssl = t->ssl;
#endif
}
static int ssl_recv(gitno_ssl *ssl, void *data, size_t len)
{
int ret;
do {
ret = gnutls_record_recv(ssl->session, data, len);
} while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
if (ret < 0) {
ssl_set_error(ret);
return -1;
}
return ret;
} }
int gitno_recv(gitno_buffer *buf) int gitno_recv(gitno_buffer *buf)
{ {
int ret; int ret;
#ifdef GIT_GNUTLS
if (buf->ssl != NULL) {
if ((ret = ssl_recv(buf->ssl, buf->data + buf->offset, buf->len - buf->offset)) < 0)
return -1;
} else {
ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0);
if (ret < 0) {
net_set_error("Error receiving socket data");
return -1;
}
}
#else
ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0); ret = p_recv(buf->fd, buf->data + buf->offset, buf->len - buf->offset, 0);
if (ret < 0) { if (ret < 0) {
net_set_error("Error receiving socket data"); net_set_error("Error receiving socket data");
return -1; return -1;
} }
#endif
buf->offset += ret; buf->offset += ret;
return ret; return ret;
...@@ -92,7 +139,44 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons) ...@@ -92,7 +139,44 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons)
buf->offset -= cons; buf->offset -= cons;
} }
int gitno_connect(GIT_SOCKET *sock, const char *host, const char *port) #ifdef GIT_GNUTLS
static int ssl_setup(git_transport *t)
{
int ret;
if ((ret = gnutls_global_init()) < 0)
return ssl_set_error(ret);
if ((ret = gnutls_certificate_allocate_credentials(&t->ssl.cred)) < 0)
return ssl_set_error(ret);
gnutls_init(&t->ssl.session, GNUTLS_CLIENT);
//gnutls_certificate_set_verify_function(ssl->cred, SSL_VERIFY_NONE);
gnutls_credentials_set(t->ssl.session, GNUTLS_CRD_CERTIFICATE, t->ssl.cred);
if ((ret = gnutls_priority_set_direct (t->ssl.session, "NORMAL", NULL)) < 0)
return ssl_set_error(ret);
gnutls_transport_set_ptr(t->ssl.session, (gnutls_transport_ptr_t) t->socket);
do {
ret = gnutls_handshake(t->ssl.session);
} while (ret < 0 && !gnutls_error_is_fatal(ret));
if (ret < 0) {
ssl_set_error(ret);
goto on_error;
}
return 0;
on_error:
gnutls_deinit(t->ssl.session);
return -1;
}
#endif
int gitno_connect(git_transport *t, const char *host, const char *port)
{ {
struct addrinfo *info = NULL, *p; struct addrinfo *info = NULL, *p;
struct addrinfo hints; struct addrinfo hints;
...@@ -129,20 +213,51 @@ int gitno_connect(GIT_SOCKET *sock, const char *host, const char *port) ...@@ -129,20 +213,51 @@ int gitno_connect(GIT_SOCKET *sock, const char *host, const char *port)
return -1; return -1;
} }
t->socket = s;
freeaddrinfo(info); freeaddrinfo(info);
*sock = s;
#ifdef GIT_GNUTLS
if (t->encrypt && ssl_setup(t) < 0)
return -1;
#endif
return 0; return 0;
} }
int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags) #ifdef GIT_GNUTLS
static int send_ssl(gitno_ssl *ssl, const char *msg, size_t len)
{ {
int ret; int ret;
size_t off = 0; size_t off = 0;
while (off < len) { while (off < len) {
errno = 0; ret = gnutls_record_send(ssl->session, msg + off, len - off);
if (ret < 0) {
if (gnutls_error_is_fatal(ret))
return ssl_set_error(ret);
ret = p_send(s, msg + off, len - off, flags); ret = 0;
}
off += ret;
}
return off;
}
#endif
int gitno_send(git_transport *t, const char *msg, size_t len, int flags)
{
int ret;
size_t off = 0;
#ifdef GIT_GNUTLS
if (t->encrypt)
return send_ssl(&t->ssl, msg, len);
#endif
while (off < len) {
errno = 0;
ret = p_send(t->socket, msg + off, len - off, flags);
if (ret < 0) { if (ret < 0) {
net_set_error("Error sending data"); net_set_error("Error sending data");
return -1; return -1;
......
...@@ -8,21 +8,29 @@ ...@@ -8,21 +8,29 @@
#define INCLUDE_netops_h__ #define INCLUDE_netops_h__
#include "posix.h" #include "posix.h"
#include "transport.h"
#ifdef GIT_GNUTLS
# include <gnutls/gnutls.h>
#endif
typedef struct gitno_buffer { typedef struct gitno_buffer {
char *data; char *data;
size_t len; size_t len;
size_t offset; size_t offset;
GIT_SOCKET fd; GIT_SOCKET fd;
#ifdef GIT_GNUTLS
struct gitno_ssl *ssl;
#endif
} gitno_buffer; } gitno_buffer;
void gitno_buffer_setup(gitno_buffer *buf, char *data, unsigned int len, GIT_SOCKET fd); void gitno_buffer_setup(git_transport *t, gitno_buffer *buf, char *data, unsigned int len);
int gitno_recv(gitno_buffer *buf); int gitno_recv(gitno_buffer *buf);
void gitno_consume(gitno_buffer *buf, const char *ptr); void gitno_consume(gitno_buffer *buf, const char *ptr);
void gitno_consume_n(gitno_buffer *buf, size_t cons); void gitno_consume_n(gitno_buffer *buf, size_t cons);
int gitno_connect(GIT_SOCKET *s, const char *host, const char *port); GIT_SOCKET gitno_connect(git_transport *t, const char *host, const char *port);
int gitno_send(GIT_SOCKET s, const char *msg, size_t len, int flags); int gitno_send(git_transport *t, const char *msg, size_t len, int flags);
int gitno_close(GIT_SOCKET s); int gitno_close(GIT_SOCKET s);
int gitno_send_chunk_size(int s, size_t len); int gitno_send_chunk_size(int s, size_t len);
int gitno_select_in(gitno_buffer *buf, long int sec, long int usec); int gitno_select_in(gitno_buffer *buf, long int sec, long int usec);
......
...@@ -281,12 +281,6 @@ int git_pkt_buffer_flush(git_buf *buf) ...@@ -281,12 +281,6 @@ int git_pkt_buffer_flush(git_buf *buf)
return git_buf_put(buf, pkt_flush_str, strlen(pkt_flush_str)); return git_buf_put(buf, pkt_flush_str, strlen(pkt_flush_str));
} }
int git_pkt_send_flush(GIT_SOCKET s)
{
return gitno_send(s, pkt_flush_str, strlen(pkt_flush_str), 0);
}
static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps, git_buf *buf) static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps, git_buf *buf)
{ {
char capstr[20]; char capstr[20];
......
...@@ -17,7 +17,7 @@ static struct { ...@@ -17,7 +17,7 @@ static struct {
} transports[] = { } transports[] = {
{"git://", git_transport_git}, {"git://", git_transport_git},
{"http://", git_transport_http}, {"http://", git_transport_http},
{"https://", git_transport_dummy}, {"https://", git_transport_https},
{"file://", git_transport_local}, {"file://", git_transport_local},
{"git+ssh://", git_transport_dummy}, {"git+ssh://", git_transport_dummy},
{"ssh+git://", git_transport_dummy}, {"ssh+git://", git_transport_dummy},
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include "git2/net.h" #include "git2/net.h"
#include "git2/indexer.h" #include "git2/indexer.h"
#include "vector.h" #include "vector.h"
#include "posix.h"
#include "common.h"
#define GIT_CAP_OFS_DELTA "ofs-delta" #define GIT_CAP_OFS_DELTA "ofs-delta"
...@@ -53,7 +55,12 @@ struct git_transport { ...@@ -53,7 +55,12 @@ struct git_transport {
* Whether we want to push or fetch * Whether we want to push or fetch
*/ */
int direction : 1, /* 0 fetch, 1 push */ int direction : 1, /* 0 fetch, 1 push */
connected : 1; connected : 1,
encrypt : 1;
#ifdef GIT_GNUTLS
struct gitno_ssl ssl;
#endif
GIT_SOCKET socket;
/** /**
* Connect and store the remote heads * Connect and store the remote heads
*/ */
...@@ -94,6 +101,7 @@ int git_transport_new(struct git_transport **transport, const char *url); ...@@ -94,6 +101,7 @@ int git_transport_new(struct git_transport **transport, const char *url);
int git_transport_local(struct git_transport **transport); int git_transport_local(struct git_transport **transport);
int git_transport_git(struct git_transport **transport); int git_transport_git(struct git_transport **transport);
int git_transport_http(struct git_transport **transport); int git_transport_http(struct git_transport **transport);
int git_transport_https(struct git_transport **transport);
int git_transport_dummy(struct git_transport **transport); int git_transport_dummy(struct git_transport **transport);
/** /**
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
typedef struct { typedef struct {
git_transport parent; git_transport parent;
git_protocol proto; git_protocol proto;
GIT_SOCKET socket;
git_vector refs; git_vector refs;
git_remote_head **heads; git_remote_head **heads;
git_transport_caps caps; git_transport_caps caps;
...@@ -77,7 +76,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) ...@@ -77,7 +76,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
return 0; return 0;
} }
static int send_request(GIT_SOCKET s, const char *cmd, const char *url) static int send_request(git_transport *t, const char *cmd, const char *url)
{ {
int error; int error;
git_buf request = GIT_BUF_INIT; git_buf request = GIT_BUF_INIT;
...@@ -86,7 +85,7 @@ static int send_request(GIT_SOCKET s, const char *cmd, const char *url) ...@@ -86,7 +85,7 @@ static int send_request(GIT_SOCKET s, const char *cmd, const char *url)
if (error < 0) if (error < 0)
goto cleanup; goto cleanup;
error = gitno_send(s, request.ptr, request.size, 0); error = gitno_send(t, request.ptr, request.size, 0);
cleanup: cleanup:
git_buf_free(&request); git_buf_free(&request);
...@@ -102,9 +101,6 @@ static int do_connect(transport_git *t, const char *url) ...@@ -102,9 +101,6 @@ static int do_connect(transport_git *t, const char *url)
{ {
char *host, *port; char *host, *port;
const char prefix[] = "git://"; const char prefix[] = "git://";
int error;
t->socket = INVALID_SOCKET;
if (!git__prefixcmp(url, prefix)) if (!git__prefixcmp(url, prefix))
url += strlen(prefix); url += strlen(prefix);
...@@ -112,24 +108,22 @@ static int do_connect(transport_git *t, const char *url) ...@@ -112,24 +108,22 @@ static int do_connect(transport_git *t, const char *url)
if (gitno_extract_host_and_port(&host, &port, url, GIT_DEFAULT_PORT) < 0) if (gitno_extract_host_and_port(&host, &port, url, GIT_DEFAULT_PORT) < 0)
return -1; return -1;
if ((error = gitno_connect(&t->socket, host, port)) == 0) { if (gitno_connect((git_transport *)t, host, port) < 0)
error = send_request(t->socket, NULL, url); goto on_error;
}
if (send_request((git_transport *)t, NULL, url) < 0)
goto on_error;
git__free(host); git__free(host);
git__free(port); git__free(port);
if (error < 0 && t->socket != INVALID_SOCKET) {
gitno_close(t->socket);
t->socket = INVALID_SOCKET;
}
if (t->socket == INVALID_SOCKET) {
giterr_set(GITERR_NET, "Failed to connect to the host");
return -1;
}
return 0; return 0;
on_error:
git__free(host);
git__free(port);
gitno_close(t->parent.socket);
return -1;
} }
/* /*
...@@ -215,7 +209,7 @@ static int git_connect(git_transport *transport, int direction) ...@@ -215,7 +209,7 @@ static int git_connect(git_transport *transport, int direction)
if (do_connect(t, transport->url) < 0) if (do_connect(t, transport->url) < 0)
goto cleanup; goto cleanup;
gitno_buffer_setup(&t->buf, t->buff, sizeof(t->buff), t->socket); gitno_buffer_setup(transport, &t->buf, t->buff, sizeof(t->buff));
t->parent.connected = 1; t->parent.connected = 1;
if (store_refs(t) < 0) if (store_refs(t) < 0)
...@@ -308,7 +302,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -308,7 +302,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c
if (git_fetch_setup_walk(&walk, repo) < 0) if (git_fetch_setup_walk(&walk, repo) < 0)
goto on_error; goto on_error;
if (gitno_send(t->socket, data.ptr, data.size, 0) < 0) if (gitno_send(transport, data.ptr, data.size, 0) < 0)
goto on_error; goto on_error;
git_buf_clear(&data); git_buf_clear(&data);
...@@ -328,7 +322,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -328,7 +322,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c
if (git_buf_oom(&data)) if (git_buf_oom(&data))
goto on_error; goto on_error;
if (gitno_send(t->socket, data.ptr, data.size, 0) < 0) if (gitno_send(transport, data.ptr, data.size, 0) < 0)
goto on_error; goto on_error;
pkt_type = recv_pkt(buf); pkt_type = recv_pkt(buf);
...@@ -351,7 +345,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c ...@@ -351,7 +345,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c
git_buf_clear(&data); git_buf_clear(&data);
git_pkt_buffer_flush(&data); git_pkt_buffer_flush(&data);
git_pkt_buffer_done(&data); git_pkt_buffer_done(&data);
if (gitno_send(t->socket, data.ptr, data.size, 0) < 0) if (gitno_send(transport, data.ptr, data.size, 0) < 0)
goto on_error; goto on_error;
git_buf_free(&data); git_buf_free(&data);
...@@ -392,7 +386,7 @@ static int git_download_pack(git_transport *transport, git_repository *repo, git ...@@ -392,7 +386,7 @@ static int git_download_pack(git_transport *transport, git_repository *repo, git
if (pkt->type == GIT_PKT_PACK) { if (pkt->type == GIT_PKT_PACK) {
git__free(pkt); git__free(pkt);
return git_fetch__download_pack(buf->data, buf->offset, t->socket, repo, bytes, stats); return git_fetch__download_pack(buf->data, buf->offset, transport, repo, bytes, stats);
} }
/* For now we don't care about anything */ /* For now we don't care about anything */
...@@ -406,12 +400,15 @@ static int git_download_pack(git_transport *transport, git_repository *repo, git ...@@ -406,12 +400,15 @@ static int git_download_pack(git_transport *transport, git_repository *repo, git
return read_bytes; return read_bytes;
} }
static int git_close(git_transport *transport) static int git_close(git_transport *t)
{ {
transport_git *t = (transport_git*) transport; git_buf buf = GIT_BUF_INIT;
if (git_pkt_buffer_flush(&buf) < 0)
return -1;
/* Can't do anything if there's an error, so don't bother checking */ /* Can't do anything if there's an error, so don't bother checking */
git_pkt_send_flush(t->socket); gitno_send(t, buf.ptr, buf.size, 0);
if (gitno_close(t->socket) < 0) { if (gitno_close(t->socket) < 0) {
giterr_set(GITERR_NET, "Failed to close socket"); giterr_set(GITERR_NET, "Failed to close socket");
return -1; return -1;
......
...@@ -32,7 +32,6 @@ typedef struct { ...@@ -32,7 +32,6 @@ typedef struct {
git_protocol proto; git_protocol proto;
git_vector refs; git_vector refs;
git_vector common; git_vector common;
GIT_SOCKET socket;
git_buf buf; git_buf buf;
git_remote_head **heads; git_remote_head **heads;
int error; int error;
...@@ -43,6 +42,7 @@ typedef struct { ...@@ -43,6 +42,7 @@ typedef struct {
enum last_cb last_cb; enum last_cb last_cb;
http_parser parser; http_parser parser;
char *content_type; char *content_type;
char *path;
char *host; char *host;
char *port; char *port;
char *service; char *service;
...@@ -52,12 +52,9 @@ typedef struct { ...@@ -52,12 +52,9 @@ typedef struct {
#endif #endif
} transport_http; } transport_http;
static int gen_request(git_buf *buf, const char *url, const char *host, const char *op, static int gen_request(git_buf *buf, const char *path, const char *host, const char *op,
const char *service, ssize_t content_length, int ls) const char *service, ssize_t content_length, int ls)
{ {
const char *path = url;
path = strchr(path, '/');
if (path == NULL) /* Is 'git fetch http://host.com/' valid? */ if (path == NULL) /* Is 'git fetch http://host.com/' valid? */
path = "/"; path = "/";
...@@ -85,15 +82,12 @@ static int gen_request(git_buf *buf, const char *url, const char *host, const ch ...@@ -85,15 +82,12 @@ static int gen_request(git_buf *buf, const char *url, const char *host, const ch
static int do_connect(transport_http *t, const char *host, const char *port) static int do_connect(transport_http *t, const char *host, const char *port)
{ {
GIT_SOCKET s;
if (t->parent.connected && http_should_keep_alive(&t->parser)) if (t->parent.connected && http_should_keep_alive(&t->parser))
return 0; return 0;
if (gitno_connect(&s, host, port) < 0) if (gitno_connect((git_transport *) t, host, port) < 0)
return -1; return -1;
t->socket = s;
t->parent.connected = 1; t->parent.connected = 1;
return 0; return 0;
...@@ -231,7 +225,7 @@ static int store_refs(transport_http *t) ...@@ -231,7 +225,7 @@ static int store_refs(transport_http *t)
settings.on_body = on_body_store_refs; settings.on_body = on_body_store_refs;
settings.on_message_complete = on_message_complete; settings.on_message_complete = on_message_complete;
gitno_buffer_setup(&buf, buffer, sizeof(buffer), t->socket); gitno_buffer_setup((git_transport *)t, &buf, buffer, sizeof(buffer));
while(1) { while(1) {
size_t parsed; size_t parsed;
...@@ -267,7 +261,8 @@ static int http_connect(git_transport *transport, int direction) ...@@ -267,7 +261,8 @@ static int http_connect(git_transport *transport, int direction)
int ret; int ret;
git_buf request = GIT_BUF_INIT; git_buf request = GIT_BUF_INIT;
const char *service = "upload-pack"; const char *service = "upload-pack";
const char *url = t->parent.url, *prefix = "http://"; const char *url = t->parent.url, *prefix_http = "http://", *prefix_https = "https://";
const char *default_port;
if (direction == GIT_DIR_PUSH) { if (direction == GIT_DIR_PUSH) {
giterr_set(GITERR_NET, "Pushing over HTTP is not implemented"); giterr_set(GITERR_NET, "Pushing over HTTP is not implemented");
...@@ -278,10 +273,19 @@ static int http_connect(git_transport *transport, int direction) ...@@ -278,10 +273,19 @@ static int http_connect(git_transport *transport, int direction)
if (git_vector_init(&t->refs, 16, NULL) < 0) if (git_vector_init(&t->refs, 16, NULL) < 0)
return -1; return -1;
if (!git__prefixcmp(url, prefix)) if (!git__prefixcmp(url, prefix_http)) {
url += strlen(prefix); url = t->parent.url + strlen(prefix_http);
default_port = "80";
}
if (!git__prefixcmp(url, prefix_https)) {
url += strlen(prefix_https);
default_port = "443";
}
t->path = strchr(url, '/');
if ((ret = gitno_extract_host_and_port(&t->host, &t->port, url, "80")) < 0) if ((ret = gitno_extract_host_and_port(&t->host, &t->port, url, default_port)) < 0)
goto cleanup; goto cleanup;
t->service = git__strdup(service); t->service = git__strdup(service);
...@@ -291,12 +295,13 @@ static int http_connect(git_transport *transport, int direction) ...@@ -291,12 +295,13 @@ static int http_connect(git_transport *transport, int direction)
goto cleanup; goto cleanup;
/* Generate and send the HTTP request */ /* Generate and send the HTTP request */
if ((ret = gen_request(&request, url, t->host, "GET", service, 0, 1)) < 0) { if ((ret = gen_request(&request, t->path, t->host, "GET", service, 0, 1)) < 0) {
giterr_set(GITERR_NET, "Failed to generate request"); giterr_set(GITERR_NET, "Failed to generate request");
goto cleanup; goto cleanup;
} }
if ((ret = gitno_send(t->socket, request.ptr, request.size, 0)) < 0)
if (gitno_send(transport, request.ptr, request.size, 0) < 0)
goto cleanup; goto cleanup;
ret = store_refs(t); ret = store_refs(t);
...@@ -403,7 +408,7 @@ static int parse_response(transport_http *t) ...@@ -403,7 +408,7 @@ static int parse_response(transport_http *t)
settings.on_body = on_body_parse_response; settings.on_body = on_body_parse_response;
settings.on_message_complete = on_message_complete; settings.on_message_complete = on_message_complete;
gitno_buffer_setup(&buf, buffer, sizeof(buffer), t->socket); gitno_buffer_setup((git_transport *)t, &buf, buffer, sizeof(buffer));
while(1) { while(1) {
size_t parsed; size_t parsed;
...@@ -437,13 +442,9 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo, ...@@ -437,13 +442,9 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo,
git_oid oid; git_oid oid;
git_pkt_ack *pkt; git_pkt_ack *pkt;
git_vector *common = &t->common; git_vector *common = &t->common;
const char *prefix = "http://", *url = t->parent.url;
git_buf request = GIT_BUF_INIT, data = GIT_BUF_INIT; git_buf request = GIT_BUF_INIT, data = GIT_BUF_INIT;
gitno_buffer_setup(&buf, buff, sizeof(buff), t->socket);
/* TODO: Store url in the transport */ gitno_buffer_setup(transport, &buf, buff, sizeof(buff));
if (!git__prefixcmp(url, prefix))
url += strlen(prefix);
if (git_vector_init(common, 16, NULL) < 0) if (git_vector_init(common, 16, NULL) < 0)
return -1; return -1;
...@@ -474,13 +475,13 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo, ...@@ -474,13 +475,13 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo,
git_pkt_buffer_done(&data); git_pkt_buffer_done(&data);
if ((ret = gen_request(&request, url, t->host, "POST", "upload-pack", data.size, 0)) < 0) if ((ret = gen_request(&request, t->path, t->host, "POST", "upload-pack", data.size, 0)) < 0)
goto cleanup; goto cleanup;
if ((ret = gitno_send(t->socket, request.ptr, request.size, 0)) < 0) if ((ret = gitno_send(transport, request.ptr, request.size, 0)) < 0)
goto cleanup; goto cleanup;
if ((ret = gitno_send(t->socket, data.ptr, data.size, 0)) < 0) if ((ret = gitno_send(transport, data.ptr, data.size, 0)) < 0)
goto cleanup; goto cleanup;
git_buf_clear(&request); git_buf_clear(&request);
...@@ -547,7 +548,7 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi ...@@ -547,7 +548,7 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi
git_indexer_stream *idx = NULL; git_indexer_stream *idx = NULL;
download_pack_cbdata data; download_pack_cbdata data;
gitno_buffer_setup(&buf, buffer, sizeof(buffer), t->socket); gitno_buffer_setup(transport, &buf, buffer, sizeof(buffer));
if (memcmp(oldbuf->ptr, "PACK", strlen("PACK"))) { if (memcmp(oldbuf->ptr, "PACK", strlen("PACK"))) {
giterr_set(GITERR_NET, "The pack doesn't start with a pack signature"); giterr_set(GITERR_NET, "The pack doesn't start with a pack signature");
...@@ -557,7 +558,6 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi ...@@ -557,7 +558,6 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi
if (git_indexer_stream_new(&idx, git_repository_path(repo)) < 0) if (git_indexer_stream_new(&idx, git_repository_path(repo)) < 0)
return -1; return -1;
/* /*
* This is part of the previous response, so we don't want to * This is part of the previous response, so we don't want to
* re-init the parser, just set these two callbacks. * re-init the parser, just set these two callbacks.
...@@ -576,6 +576,9 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi ...@@ -576,6 +576,9 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi
if (git_indexer_stream_add(idx, git_buf_cstr(oldbuf), git_buf_len(oldbuf), stats) < 0) if (git_indexer_stream_add(idx, git_buf_cstr(oldbuf), git_buf_len(oldbuf), stats) < 0)
goto on_error; goto on_error;
gitno_buffer_setup(transport, &buf, buffer, sizeof(buffer));
do { do {
size_t parsed; size_t parsed;
...@@ -603,9 +606,7 @@ on_error: ...@@ -603,9 +606,7 @@ on_error:
static int http_close(git_transport *transport) static int http_close(git_transport *transport)
{ {
transport_http *t = (transport_http *) transport; if (gitno_close(transport->socket) < 0) {
if (gitno_close(t->socket) < 0) {
giterr_set(GITERR_OS, "Failed to close the socket: %s", strerror(errno)); giterr_set(GITERR_OS, "Failed to close the socket: %s", strerror(errno));
return -1; return -1;
} }
...@@ -680,3 +681,22 @@ int git_transport_http(git_transport **out) ...@@ -680,3 +681,22 @@ int git_transport_http(git_transport **out)
*out = (git_transport *) t; *out = (git_transport *) t;
return 0; return 0;
} }
int git_transport_https(git_transport **out)
{
#ifdef GIT_GNUTLS
transport_http *t;
if (git_transport_http((git_transport **)&t) < 0)
return -1;
t->parent.encrypt = 1;
*out = (git_transport *) t;
return 0;
#else
GIT_UNUSED(out);
giterr_set(GITERR_NET, "HTTPS support not available");
return -1;
#endif
}
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