Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
966fbdcb
Commit
966fbdcb
authored
Jun 05, 2012
by
Vicent Martí
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #697 from carlosmn/ssl
Add HTTPS support
parents
eadc0e03
250b95b2
Show whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
456 additions
and
80 deletions
+456
-80
CMakeLists.txt
+9
-2
include/git2/errors.h
+1
-0
include/git2/remote.h
+9
-0
src/common.h
+0
-1
src/fetch.c
+2
-2
src/fetch.h
+1
-1
src/netops.c
+313
-7
src/netops.h
+10
-3
src/pkt.c
+0
-6
src/remote.c
+10
-0
src/remote.h
+2
-1
src/transport.c
+1
-1
src/transport.h
+23
-1
src/transports/git.c
+23
-26
src/transports/http.c
+52
-29
No files found.
CMakeLists.txt
View file @
966fbdcb
...
...
@@ -89,6 +89,13 @@ IF (NOT CMAKE_BUILD_TYPE)
SET
(
CMAKE_BUILD_TYPE
"Debug"
CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE
)
ENDIF
()
FIND_PACKAGE
(
OpenSSL
)
IF
(
OPENSSL_FOUND
)
ADD_DEFINITIONS
(
-DGIT_SSL
)
INCLUDE_DIRECTORIES
(
${
OPENSSL_INCLUDE_DIR
}
)
SET
(
SSL_LIBRARIES
${
OPENSSL_LIBRARIES
}
)
ENDIF
()
IF
(
THREADSAFE
)
IF
(
NOT WIN32
)
find_package
(
Threads REQUIRED
)
...
...
@@ -121,7 +128,7 @@ ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
TARGET_LINK_LIBRARIES
(
git2 socket nsl
)
ENDIF
()
TARGET_LINK_LIBRARIES
(
git2
${
CMAKE_THREAD_LIBS_INIT
}
)
TARGET_LINK_LIBRARIES
(
git2
${
CMAKE_THREAD_LIBS_INIT
}
${
SSL_LIBRARIES
}
)
SET_TARGET_PROPERTIES
(
git2 PROPERTIES VERSION
${
LIBGIT2_VERSION_STRING
}
)
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
)
...
...
@@ -157,7 +164,7 @@ IF (BUILD_CLAR)
WORKING_DIRECTORY
${
CLAR_PATH
}
)
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
}
${
SSL_LIBRARIES
}
)
IF (WIN32)
TARGET_LINK_LIBRARIES(libgit2_clar ws2_32)
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "
(
Solaris|SunOS
)
")
...
...
include/git2/errors.h
View file @
966fbdcb
...
...
@@ -88,6 +88,7 @@ typedef enum {
GITERR_TAG
,
GITERR_TREE
,
GITERR_INDEXER
,
GITERR_SSL
,
}
git_error_t
;
/**
...
...
include/git2/remote.h
View file @
966fbdcb
...
...
@@ -229,6 +229,15 @@ GIT_EXTERN(int) git_remote_list(git_strarray *remotes_list, git_repository *repo
*/
GIT_EXTERN
(
int
)
git_remote_add
(
git_remote
**
out
,
git_repository
*
repo
,
const
char
*
name
,
const
char
*
url
);
/**
* Choose whether to check the server's certificate (applies to HTTPS only)
*
* @param remote the remote to configure
* @param check whether to check the server's certificate (defaults to yes)
*/
GIT_EXTERN
(
void
)
git_remote_check_cert
(
git_remote
*
remote
,
int
check
);
/** @} */
GIT_END_DECL
#endif
src/common.h
View file @
966fbdcb
...
...
@@ -65,7 +65,6 @@ void giterr_clear(void);
void
giterr_set_str
(
int
error_class
,
const
char
*
string
);
void
giterr_set_regex
(
const
regex_t
*
regex
,
int
error_code
);
#include "util.h"
...
...
src/fetch.c
View file @
966fbdcb
...
...
@@ -110,7 +110,7 @@ int git_fetch_download_pack(git_remote *remote, git_off_t *bytes, git_indexer_st
int
git_fetch__download_pack
(
const
char
*
buffered
,
size_t
buffered_size
,
GIT_SOCKET
fd
,
git_transport
*
t
,
git_repository
*
repo
,
git_off_t
*
bytes
,
git_indexer_stats
*
stats
)
...
...
@@ -120,7 +120,7 @@ int git_fetch__download_pack(
gitno_buffer
buf
;
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"
)))
{
giterr_set
(
GITERR_NET
,
"The pack doesn't start with the signature"
);
...
...
src/fetch.h
View file @
966fbdcb
...
...
@@ -12,7 +12,7 @@
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
(
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
);
int
git_fetch_setup_walk
(
git_revwalk
**
out
,
git_repository
*
repo
);
...
...
src/netops.c
View file @
966fbdcb
...
...
@@ -18,13 +18,20 @@
# endif
#endif
#ifdef GIT_SSL
# include <openssl/ssl.h>
# include <openssl/x509v3.h>
#endif
#include <ctype.h>
#include <arpa/inet.h>
#include "git2/errors.h"
#include "common.h"
#include "netops.h"
#include "posix.h"
#include "buffer.h"
#include "transport.h"
#ifdef GIT_WIN32
static
void
net_set_error
(
const
char
*
str
)
...
...
@@ -45,25 +52,68 @@ static void net_set_error(const char *str)
}
#endif
void
gitno_buffer_setup
(
gitno_buffer
*
buf
,
char
*
data
,
unsigned
int
len
,
GIT_SOCKET
fd
)
#ifdef GIT_SSL
static
int
ssl_set_error
(
gitno_ssl
*
ssl
,
int
error
)
{
int
err
;
err
=
SSL_get_error
(
ssl
->
ssl
,
error
);
giterr_set
(
GITERR_NET
,
"SSL error: %s"
,
ERR_error_string
(
err
,
NULL
));
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
(
data
,
0x0
,
len
);
buf
->
data
=
data
;
buf
->
len
=
len
;
buf
->
offset
=
0
;
buf
->
fd
=
fd
;
buf
->
fd
=
t
->
socket
;
#ifdef GIT_SSL
if
(
t
->
encrypt
)
buf
->
ssl
=
&
t
->
ssl
;
#endif
}
#ifdef GIT_SSL
static
int
ssl_recv
(
gitno_ssl
*
ssl
,
void
*
data
,
size_t
len
)
{
int
ret
;
do
{
ret
=
SSL_read
(
ssl
->
ssl
,
data
,
len
);
}
while
(
SSL_get_error
(
ssl
->
ssl
,
ret
)
==
SSL_ERROR_WANT_READ
);
if
(
ret
<
0
)
return
ssl_set_error
(
ssl
,
ret
);
return
ret
;
}
#endif
int
gitno_recv
(
gitno_buffer
*
buf
)
{
int
ret
;
#ifdef GIT_SSL
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
);
if
(
ret
<
0
)
{
net_set_error
(
"Error receiving socket data"
);
return
-
1
;
}
#endif
buf
->
offset
+=
ret
;
return
ret
;
...
...
@@ -92,7 +142,237 @@ void gitno_consume_n(gitno_buffer *buf, size_t cons)
buf
->
offset
-=
cons
;
}
int
gitno_connect
(
GIT_SOCKET
*
sock
,
const
char
*
host
,
const
char
*
port
)
int
gitno_ssl_teardown
(
git_transport
*
t
)
{
int
ret
=
ret
;
if
(
!
t
->
encrypt
)
return
0
;
#ifdef GIT_SSL
do
{
ret
=
SSL_shutdown
(
t
->
ssl
.
ssl
);
}
while
(
ret
==
0
);
if
(
ret
<
0
)
return
ssl_set_error
(
&
t
->
ssl
,
ret
);
SSL_free
(
t
->
ssl
.
ssl
);
SSL_CTX_free
(
t
->
ssl
.
ctx
);
#endif
return
0
;
}
#ifdef GIT_SSL
/* Match host names according to RFC 2818 rules */
static
int
match_host
(
const
char
*
pattern
,
const
char
*
host
)
{
for
(;;)
{
char
c
=
tolower
(
*
pattern
++
);
if
(
c
==
'\0'
)
return
*
host
?
-
1
:
0
;
if
(
c
==
'*'
)
{
c
=
*
pattern
;
/* '*' at the end matches everything left */
if
(
c
==
'\0'
)
return
0
;
/*
* We've found a pattern, so move towards the next matching
* char. The '.' is handled specially because wildcards aren't
* allowed to cross subdomains.
*/
while
(
*
host
)
{
char
h
=
tolower
(
*
host
);
if
(
c
==
h
)
return
match_host
(
pattern
,
host
++
);
if
(
h
==
'.'
)
return
match_host
(
pattern
,
host
);
host
++
;
}
return
-
1
;
}
if
(
c
!=
tolower
(
*
host
++
))
return
-
1
;
}
return
-
1
;
}
static
int
check_host_name
(
const
char
*
name
,
const
char
*
host
)
{
if
(
!
strcasecmp
(
name
,
host
))
return
0
;
if
(
match_host
(
name
,
host
)
<
0
)
return
-
1
;
return
0
;
}
static
int
verify_server_cert
(
git_transport
*
t
,
const
char
*
host
)
{
X509
*
cert
;
X509_NAME
*
peer_name
;
ASN1_STRING
*
str
;
unsigned
char
*
peer_cn
=
NULL
;
int
matched
=
-
1
,
type
=
GEN_DNS
;
GENERAL_NAMES
*
alts
;
struct
in6_addr
addr6
;
struct
in_addr
addr4
;
void
*
addr
;
int
i
=
-
1
,
j
;
/* Try to parse the host as an IP address to see if it is */
if
(
inet_pton
(
AF_INET
,
host
,
&
addr4
))
{
type
=
GEN_IPADD
;
addr
=
&
addr4
;
}
else
{
if
(
inet_pton
(
AF_INET6
,
host
,
&
addr6
))
{
type
=
GEN_IPADD
;
addr
=
&
addr6
;
}
}
cert
=
SSL_get_peer_certificate
(
t
->
ssl
.
ssl
);
/* Check the alternative names */
alts
=
X509_get_ext_d2i
(
cert
,
NID_subject_alt_name
,
NULL
,
NULL
);
if
(
alts
)
{
int
num
;
num
=
sk_GENERAL_NAME_num
(
alts
);
for
(
i
=
0
;
i
<
num
&&
matched
!=
1
;
i
++
)
{
const
GENERAL_NAME
*
gn
=
sk_GENERAL_NAME_value
(
alts
,
i
);
const
char
*
name
=
(
char
*
)
ASN1_STRING_data
(
gn
->
d
.
ia5
);
size_t
namelen
=
(
size_t
)
ASN1_STRING_length
(
gn
->
d
.
ia5
);
/* Skip any names of a type we're not looking for */
if
(
gn
->
type
!=
type
)
continue
;
if
(
type
==
GEN_DNS
)
{
/* If it contains embedded NULs, don't even try */
if
(
memchr
(
name
,
'\0'
,
namelen
))
continue
;
if
(
check_host_name
(
name
,
host
)
<
0
)
matched
=
0
;
else
matched
=
1
;
}
else
if
(
type
==
GEN_IPADD
)
{
/* Here name isn't so much a name but a binary representation of the IP */
matched
=
!!
memcmp
(
name
,
addr
,
namelen
);
}
}
}
GENERAL_NAMES_free
(
alts
);
if
(
matched
==
0
)
goto
on_error
;
if
(
matched
==
1
)
return
0
;
/* If no alternative names are available, check the common name */
peer_name
=
X509_get_subject_name
(
cert
);
if
(
peer_name
==
NULL
)
goto
on_error
;
if
(
peer_name
)
{
/* Get the index of the last CN entry */
while
((
j
=
X509_NAME_get_index_by_NID
(
peer_name
,
NID_commonName
,
i
))
>=
0
)
i
=
j
;
}
if
(
i
<
0
)
goto
on_error
;
str
=
X509_NAME_ENTRY_get_data
(
X509_NAME_get_entry
(
peer_name
,
i
));
if
(
str
==
NULL
)
goto
on_error
;
/* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */
if
(
ASN1_STRING_type
(
str
)
==
V_ASN1_UTF8STRING
)
{
int
size
=
ASN1_STRING_length
(
str
);
if
(
size
>
0
)
{
peer_cn
=
OPENSSL_malloc
(
size
+
1
);
GITERR_CHECK_ALLOC
(
peer_cn
);
memcpy
(
peer_cn
,
ASN1_STRING_data
(
str
),
size
);
peer_cn
[
size
]
=
'\0'
;
}
}
else
{
int
size
=
ASN1_STRING_to_UTF8
(
&
peer_cn
,
str
);
GITERR_CHECK_ALLOC
(
peer_cn
);
if
(
memchr
(
peer_cn
,
'\0'
,
size
))
goto
cert_fail
;
}
if
(
check_host_name
((
char
*
)
peer_cn
,
host
)
<
0
)
goto
cert_fail
;
OPENSSL_free
(
peer_cn
);
return
0
;
on_error:
OPENSSL_free
(
peer_cn
);
return
ssl_set_error
(
&
t
->
ssl
,
0
);
cert_fail:
OPENSSL_free
(
peer_cn
);
giterr_set
(
GITERR_SSL
,
"Certificate host name check failed"
);
return
-
1
;
}
static
int
ssl_setup
(
git_transport
*
t
,
const
char
*
host
)
{
int
ret
;
SSL_library_init
();
SSL_load_error_strings
();
t
->
ssl
.
ctx
=
SSL_CTX_new
(
SSLv23_method
());
if
(
t
->
ssl
.
ctx
==
NULL
)
return
ssl_set_error
(
&
t
->
ssl
,
0
);
SSL_CTX_set_mode
(
t
->
ssl
.
ctx
,
SSL_MODE_AUTO_RETRY
);
SSL_CTX_set_verify
(
t
->
ssl
.
ctx
,
SSL_VERIFY_PEER
,
NULL
);
if
(
!
SSL_CTX_set_default_verify_paths
(
t
->
ssl
.
ctx
))
return
ssl_set_error
(
&
t
->
ssl
,
0
);
t
->
ssl
.
ssl
=
SSL_new
(
t
->
ssl
.
ctx
);
if
(
t
->
ssl
.
ssl
==
NULL
)
return
ssl_set_error
(
&
t
->
ssl
,
0
);
if
((
ret
=
SSL_set_fd
(
t
->
ssl
.
ssl
,
t
->
socket
))
==
0
)
return
ssl_set_error
(
&
t
->
ssl
,
ret
);
if
((
ret
=
SSL_connect
(
t
->
ssl
.
ssl
))
<=
0
)
return
ssl_set_error
(
&
t
->
ssl
,
ret
);
if
(
t
->
check_cert
&&
verify_server_cert
(
t
,
host
)
<
0
)
return
-
1
;
return
0
;
}
#else
static
int
ssl_setup
(
git_transport
*
t
,
const
char
*
host
)
{
GIT_UNUSED
(
t
);
GIT_UNUSED
(
host
);
return
0
;
}
#endif
int
gitno_connect
(
git_transport
*
t
,
const
char
*
host
,
const
char
*
port
)
{
struct
addrinfo
*
info
=
NULL
,
*
p
;
struct
addrinfo
hints
;
...
...
@@ -129,20 +409,46 @@ int gitno_connect(GIT_SOCKET *sock, const char *host, const char *port)
return
-
1
;
}
t
->
socket
=
s
;
freeaddrinfo
(
info
);
*
sock
=
s
;
if
(
t
->
encrypt
&&
ssl_setup
(
t
,
host
)
<
0
)
return
-
1
;
return
0
;
}
int
gitno_send
(
GIT_SOCKET
s
,
const
char
*
msg
,
size_t
len
,
int
flags
)
#ifdef GIT_SSL
static
int
send_ssl
(
gitno_ssl
*
ssl
,
const
char
*
msg
,
size_t
len
)
{
int
ret
;
size_t
off
=
0
;
while
(
off
<
len
)
{
errno
=
0
;
ret
=
SSL_write
(
ssl
->
ssl
,
msg
+
off
,
len
-
off
);
if
(
ret
<=
0
)
return
ssl_set_error
(
ssl
,
ret
);
off
+=
ret
;
}
return
off
;
}
#endif
ret
=
p_send
(
s
,
msg
+
off
,
len
-
off
,
flags
);
int
gitno_send
(
git_transport
*
t
,
const
char
*
msg
,
size_t
len
,
int
flags
)
{
int
ret
;
size_t
off
=
0
;
#ifdef GIT_SSL
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
)
{
net_set_error
(
"Error sending data"
);
return
-
1
;
...
...
src/netops.h
View file @
966fbdcb
...
...
@@ -8,22 +8,29 @@
#define INCLUDE_netops_h__
#include "posix.h"
#include "transport.h"
#include "common.h"
typedef
struct
gitno_buffer
{
char
*
data
;
size_t
len
;
size_t
offset
;
GIT_SOCKET
fd
;
#ifdef GIT_SSL
struct
gitno_ssl
*
ssl
;
#endif
}
gitno_buffer
;
void
gitno_buffer_setup
(
git
no_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
);
void
gitno_consume
(
gitno_buffer
*
buf
,
const
char
*
ptr
);
void
gitno_consume_n
(
gitno_buffer
*
buf
,
size_t
cons
);
int
gitno_connect
(
GIT_SOCKET
*
s
,
const
char
*
host
,
const
char
*
port
);
int
gitno_send
(
GIT_SOCKET
s
,
const
char
*
msg
,
size_t
len
,
int
flags
);
int
gitno_connect
(
git_transport
*
t
,
const
char
*
host
,
const
char
*
port
);
int
gitno_send
(
git_transport
*
t
,
const
char
*
msg
,
size_t
len
,
int
flags
);
int
gitno_close
(
GIT_SOCKET
s
);
int
gitno_ssl_teardown
(
git_transport
*
t
);
int
gitno_send_chunk_size
(
int
s
,
size_t
len
);
int
gitno_select_in
(
gitno_buffer
*
buf
,
long
int
sec
,
long
int
usec
);
...
...
src/pkt.c
View file @
966fbdcb
...
...
@@ -281,12 +281,6 @@ int git_pkt_buffer_flush(git_buf *buf)
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
)
{
char
capstr
[
20
];
...
...
src/remote.c
View file @
966fbdcb
...
...
@@ -66,6 +66,7 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *name, con
memset
(
remote
,
0x0
,
sizeof
(
git_remote
));
remote
->
repo
=
repo
;
remote
->
check_cert
=
1
;
if
(
git_vector_init
(
&
remote
->
refs
,
32
,
NULL
)
<
0
)
return
-
1
;
...
...
@@ -108,6 +109,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name)
GITERR_CHECK_ALLOC
(
remote
);
memset
(
remote
,
0x0
,
sizeof
(
git_remote
));
remote
->
check_cert
=
1
;
remote
->
name
=
git__strdup
(
name
);
GITERR_CHECK_ALLOC
(
remote
->
name
);
...
...
@@ -291,6 +293,7 @@ int git_remote_connect(git_remote *remote, int direction)
if
(
git_transport_new
(
&
t
,
remote
->
url
)
<
0
)
return
-
1
;
t
->
check_cert
=
remote
->
check_cert
;
if
(
t
->
connect
(
t
,
direction
)
<
0
)
{
goto
on_error
;
}
...
...
@@ -512,3 +515,10 @@ on_error:
git_remote_free
(
*
out
);
return
-
1
;
}
void
git_remote_check_cert
(
git_remote
*
remote
,
int
check
)
{
assert
(
remote
);
remote
->
check_cert
=
check
;
}
src/remote.h
View file @
966fbdcb
...
...
@@ -19,7 +19,8 @@ struct git_remote {
struct
git_refspec
push
;
git_transport
*
transport
;
git_repository
*
repo
;
unsigned
int
need_pack
:
1
;
unsigned
int
need_pack
:
1
,
check_cert
;
};
#endif
src/transport.c
View file @
966fbdcb
...
...
@@ -17,7 +17,7 @@ static struct {
}
transports
[]
=
{
{
"git://"
,
git_transport_git
},
{
"http://"
,
git_transport_http
},
{
"https://"
,
git_transport_
dummy
},
{
"https://"
,
git_transport_
https
},
{
"file://"
,
git_transport_local
},
{
"git+ssh://"
,
git_transport_dummy
},
{
"ssh+git://"
,
git_transport_dummy
},
...
...
src/transport.h
View file @
966fbdcb
...
...
@@ -10,6 +10,13 @@
#include "git2/net.h"
#include "git2/indexer.h"
#include "vector.h"
#include "posix.h"
#include "common.h"
#ifdef GIT_SSL
# include <openssl/ssl.h>
# include <openssl/err.h>
#endif
#define GIT_CAP_OFS_DELTA "ofs-delta"
...
...
@@ -18,6 +25,14 @@ typedef struct git_transport_caps {
ofs_delta
:
1
;
}
git_transport_caps
;
#ifdef GIT_SSL
typedef
struct
gitno_ssl
{
SSL_CTX
*
ctx
;
SSL
*
ssl
;
}
gitno_ssl
;
#endif
/*
* A day in the life of a network operation
* ========================================
...
...
@@ -53,7 +68,13 @@ struct git_transport {
* Whether we want to push or fetch
*/
int
direction
:
1
,
/* 0 fetch, 1 push */
connected
:
1
;
connected
:
1
,
check_cert
:
1
,
encrypt
:
1
;
#ifdef GIT_SSL
struct
gitno_ssl
ssl
;
#endif
GIT_SOCKET
socket
;
/**
* Connect and store the remote heads
*/
...
...
@@ -94,6 +115,7 @@ int git_transport_new(struct git_transport **transport, const char *url);
int
git_transport_local
(
struct
git_transport
**
transport
);
int
git_transport_git
(
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
);
/**
...
...
src/transports/git.c
View file @
966fbdcb
...
...
@@ -25,7 +25,6 @@
typedef
struct
{
git_transport
parent
;
git_protocol
proto
;
GIT_SOCKET
socket
;
git_vector
refs
;
git_remote_head
**
heads
;
git_transport_caps
caps
;
...
...
@@ -77,7 +76,7 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
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
;
git_buf
request
=
GIT_BUF_INIT
;
...
...
@@ -86,7 +85,7 @@ static int send_request(GIT_SOCKET s, const char *cmd, const char *url)
if
(
error
<
0
)
goto
cleanup
;
error
=
gitno_send
(
s
,
request
.
ptr
,
request
.
size
,
0
);
error
=
gitno_send
(
t
,
request
.
ptr
,
request
.
size
,
0
);
cleanup:
git_buf_free
(
&
request
);
...
...
@@ -102,9 +101,6 @@ static int do_connect(transport_git *t, const char *url)
{
char
*
host
,
*
port
;
const
char
prefix
[]
=
"git://"
;
int
error
;
t
->
socket
=
INVALID_SOCKET
;
if
(
!
git__prefixcmp
(
url
,
prefix
))
url
+=
strlen
(
prefix
);
...
...
@@ -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
)
return
-
1
;
if
((
error
=
gitno_connect
(
&
t
->
socket
,
host
,
port
))
==
0
)
{
error
=
send_request
(
t
->
socket
,
NULL
,
url
);
}
if
(
gitno_connect
((
git_transport
*
)
t
,
host
,
port
)
<
0
)
goto
on_error
;
if
(
send_request
((
git_transport
*
)
t
,
NULL
,
url
)
<
0
)
goto
on_error
;
git__free
(
host
);
git__free
(
port
);
if
(
error
<
0
&&
t
->
socket
!=
INVALID_SOCKET
)
{
gitno_close
(
t
->
socket
);
t
->
socket
=
INVALID_SOCKET
;
}
return
0
;
if
(
t
->
socket
==
INVALID_SOCKET
)
{
giterr_set
(
GITERR_NET
,
"Failed to connect to the host"
);
on_error:
git__free
(
host
);
git__free
(
port
);
gitno_close
(
t
->
parent
.
socket
);
return
-
1
;
}
return
0
;
}
/*
...
...
@@ -215,7 +209,7 @@ static int git_connect(git_transport *transport, int direction)
if
(
do_connect
(
t
,
transport
->
url
)
<
0
)
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
;
if
(
store_refs
(
t
)
<
0
)
...
...
@@ -308,7 +302,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c
if
(
git_fetch_setup_walk
(
&
walk
,
repo
)
<
0
)
goto
on_error
;
if
(
gitno_send
(
t
->
socke
t
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
if
(
gitno_send
(
t
ranspor
t
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
goto
on_error
;
git_buf_clear
(
&
data
);
...
...
@@ -328,7 +322,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c
if
(
git_buf_oom
(
&
data
))
goto
on_error
;
if
(
gitno_send
(
t
->
socke
t
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
if
(
gitno_send
(
t
ranspor
t
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
goto
on_error
;
pkt_type
=
recv_pkt
(
buf
);
...
...
@@ -351,7 +345,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c
git_buf_clear
(
&
data
);
git_pkt_buffer_flush
(
&
data
);
git_pkt_buffer_done
(
&
data
);
if
(
gitno_send
(
t
->
socke
t
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
if
(
gitno_send
(
t
ranspor
t
,
data
.
ptr
,
data
.
size
,
0
)
<
0
)
goto
on_error
;
git_buf_free
(
&
data
);
...
...
@@ -392,7 +386,7 @@ static int git_download_pack(git_transport *transport, git_repository *repo, git
if
(
pkt
->
type
==
GIT_PKT_PACK
)
{
git__free
(
pkt
);
return
git_fetch__download_pack
(
buf
->
data
,
buf
->
offset
,
t
->
socke
t
,
repo
,
bytes
,
stats
);
return
git_fetch__download_pack
(
buf
->
data
,
buf
->
offset
,
t
ranspor
t
,
repo
,
bytes
,
stats
);
}
/* For now we don't care about anything */
...
...
@@ -406,12 +400,15 @@ static int git_download_pack(git_transport *transport, git_repository *repo, git
return
read_bytes
;
}
static
int
git_close
(
git_transport
*
t
ransport
)
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 */
git_pkt_send_flush
(
t
->
socket
);
gitno_send
(
t
,
buf
.
ptr
,
buf
.
size
,
0
);
if
(
gitno_close
(
t
->
socket
)
<
0
)
{
giterr_set
(
GITERR_NET
,
"Failed to close socket"
);
return
-
1
;
...
...
src/transports/http.c
View file @
966fbdcb
...
...
@@ -32,7 +32,6 @@ typedef struct {
git_protocol
proto
;
git_vector
refs
;
git_vector
common
;
GIT_SOCKET
socket
;
git_buf
buf
;
git_remote_head
**
heads
;
int
error
;
...
...
@@ -43,6 +42,7 @@ typedef struct {
enum
last_cb
last_cb
;
http_parser
parser
;
char
*
content_type
;
char
*
path
;
char
*
host
;
char
*
port
;
char
*
service
;
...
...
@@ -52,12 +52,9 @@ typedef struct {
#endif
}
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
*
path
=
url
;
path
=
strchr
(
path
,
'/'
);
if
(
path
==
NULL
)
/* Is 'git fetch http://host.com/' valid? */
path
=
"/"
;
...
...
@@ -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
)
{
GIT_SOCKET
s
;
if
(
t
->
parent
.
connected
&&
http_should_keep_alive
(
&
t
->
parser
))
return
0
;
if
(
gitno_connect
(
&
s
,
host
,
port
)
<
0
)
if
(
gitno_connect
(
(
git_transport
*
)
t
,
host
,
port
)
<
0
)
return
-
1
;
t
->
socket
=
s
;
t
->
parent
.
connected
=
1
;
return
0
;
...
...
@@ -231,7 +225,7 @@ static int store_refs(transport_http *t)
settings
.
on_body
=
on_body_store_refs
;
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
)
{
size_t
parsed
;
...
...
@@ -267,7 +261,8 @@ static int http_connect(git_transport *transport, int direction)
int
ret
;
git_buf
request
=
GIT_BUF_INIT
;
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
)
{
giterr_set
(
GITERR_NET
,
"Pushing over HTTP is not implemented"
);
...
...
@@ -278,10 +273,19 @@ static int http_connect(git_transport *transport, int direction)
if
(
git_vector_init
(
&
t
->
refs
,
16
,
NULL
)
<
0
)
return
-
1
;
if
(
!
git__prefixcmp
(
url
,
prefix
))
url
+=
strlen
(
prefix
);
if
(
!
git__prefixcmp
(
url
,
prefix_http
))
{
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
;
t
->
service
=
git__strdup
(
service
);
...
...
@@ -291,12 +295,13 @@ static int http_connect(git_transport *transport, int direction)
goto
cleanup
;
/* 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"
);
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
;
ret
=
store_refs
(
t
);
...
...
@@ -403,7 +408,7 @@ static int parse_response(transport_http *t)
settings
.
on_body
=
on_body_parse_response
;
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
)
{
size_t
parsed
;
...
...
@@ -437,13 +442,9 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo,
git_oid
oid
;
git_pkt_ack
*
pkt
;
git_vector
*
common
=
&
t
->
common
;
const
char
*
prefix
=
"http://"
,
*
url
=
t
->
parent
.
url
;
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 */
if
(
!
git__prefixcmp
(
url
,
prefix
))
url
+=
strlen
(
prefix
);
gitno_buffer_setup
(
transport
,
&
buf
,
buff
,
sizeof
(
buff
));
if
(
git_vector_init
(
common
,
16
,
NULL
)
<
0
)
return
-
1
;
...
...
@@ -474,13 +475,13 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo,
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
;
if
((
ret
=
gitno_send
(
t
->
socke
t
,
request
.
ptr
,
request
.
size
,
0
))
<
0
)
if
((
ret
=
gitno_send
(
t
ranspor
t
,
request
.
ptr
,
request
.
size
,
0
))
<
0
)
goto
cleanup
;
if
((
ret
=
gitno_send
(
t
->
socke
t
,
data
.
ptr
,
data
.
size
,
0
))
<
0
)
if
((
ret
=
gitno_send
(
t
ranspor
t
,
data
.
ptr
,
data
.
size
,
0
))
<
0
)
goto
cleanup
;
git_buf_clear
(
&
request
);
...
...
@@ -547,7 +548,7 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi
git_indexer_stream
*
idx
=
NULL
;
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"
)))
{
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
if
(
git_indexer_stream_new
(
&
idx
,
git_repository_path
(
repo
))
<
0
)
return
-
1
;
/*
* This is part of the previous response, so we don't want to
* re-init the parser, just set these two callbacks.
...
...
@@ -576,6 +576,8 @@ 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
)
goto
on_error
;
gitno_buffer_setup
(
transport
,
&
buf
,
buffer
,
sizeof
(
buffer
));
do
{
size_t
parsed
;
...
...
@@ -603,9 +605,10 @@ on_error:
static
int
http_close
(
git_transport
*
transport
)
{
transport_http
*
t
=
(
transport_http
*
)
transport
;
if
(
gitno_ssl_teardown
(
transport
)
<
0
)
return
-
1
;
if
(
gitno_close
(
t
->
socket
)
<
0
)
{
if
(
gitno_close
(
t
ransport
->
socket
)
<
0
)
{
giterr_set
(
GITERR_OS
,
"Failed to close the socket: %s"
,
strerror
(
errno
));
return
-
1
;
}
...
...
@@ -682,3 +685,23 @@ int git_transport_http(git_transport **out)
*
out
=
(
git_transport
*
)
t
;
return
0
;
}
int
git_transport_https
(
git_transport
**
out
)
{
#ifdef GIT_SSL
transport_http
*
t
;
if
(
git_transport_http
((
git_transport
**
)
&
t
)
<
0
)
return
-
1
;
t
->
parent
.
encrypt
=
1
;
t
->
parent
.
check_cert
=
1
;
*
out
=
(
git_transport
*
)
t
;
return
0
;
#else
GIT_UNUSED
(
out
);
giterr_set
(
GITERR_NET
,
"HTTPS support not available"
);
return
-
1
;
#endif
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment