rugged 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rugged/version.rb +1 -1
- data/vendor/libgit2/CMakeLists.txt +1 -1
- data/vendor/libgit2/deps/ntlmclient/CMakeLists.txt +1 -0
- data/vendor/libgit2/deps/ntlmclient/compat.h +0 -34
- data/vendor/libgit2/deps/ntlmclient/crypt_openssl.c +1 -1
- data/vendor/libgit2/deps/ntlmclient/ntlm.c +5 -5
- data/vendor/libgit2/deps/ntlmclient/util.c +15 -1
- data/vendor/libgit2/deps/ntlmclient/util.h +2 -1
- data/vendor/libgit2/include/git2/apply.h +2 -0
- data/vendor/libgit2/include/git2/blob.h +17 -1
- data/vendor/libgit2/include/git2/common.h +5 -0
- data/vendor/libgit2/include/git2/config.h +1 -1
- data/vendor/libgit2/include/git2/diff.h +1 -1
- data/vendor/libgit2/include/git2/index.h +2 -2
- data/vendor/libgit2/include/git2/indexer.h +2 -1
- data/vendor/libgit2/include/git2/odb.h +15 -20
- data/vendor/libgit2/include/git2/refs.h +3 -3
- data/vendor/libgit2/include/git2/repository.h +95 -52
- data/vendor/libgit2/include/git2/transport.h +1 -1
- data/vendor/libgit2/include/git2/tree.h +2 -0
- data/vendor/libgit2/include/git2/version.h +2 -2
- data/vendor/libgit2/src/blame.c +15 -10
- data/vendor/libgit2/src/blob.c +9 -0
- data/vendor/libgit2/src/clone.c +42 -21
- data/vendor/libgit2/src/config_cache.c +6 -3
- data/vendor/libgit2/src/diff_tform.c +2 -2
- data/vendor/libgit2/src/index.c +6 -5
- data/vendor/libgit2/src/indexer.c +19 -3
- data/vendor/libgit2/src/integer.h +15 -0
- data/vendor/libgit2/src/merge.c +5 -2
- data/vendor/libgit2/src/mwindow.c +3 -1
- data/vendor/libgit2/src/odb.c +4 -3
- data/vendor/libgit2/src/pack.c +10 -6
- data/vendor/libgit2/src/posix.c +32 -9
- data/vendor/libgit2/src/posix.h +9 -0
- data/vendor/libgit2/src/refdb_fs.c +4 -2
- data/vendor/libgit2/src/refs.c +20 -7
- data/vendor/libgit2/src/refs.h +1 -1
- data/vendor/libgit2/src/refspec.c +48 -32
- data/vendor/libgit2/src/remote.c +13 -7
- data/vendor/libgit2/src/repository.c +15 -15
- data/vendor/libgit2/src/repository.h +1 -1
- data/vendor/libgit2/src/thread-utils.h +24 -19
- data/vendor/libgit2/src/transports/httpclient.c +9 -4
- data/vendor/libgit2/src/transports/winhttp.c +99 -52
- data/vendor/libgit2/src/unix/posix.h +3 -0
- data/vendor/libgit2/src/win32/posix_w32.c +70 -0
- data/vendor/libgit2/src/worktree.c +8 -1
- metadata +2 -2
data/vendor/libgit2/src/posix.h
CHANGED
@@ -89,6 +89,12 @@
|
|
89
89
|
#define EAFNOSUPPORT (INT_MAX-1)
|
90
90
|
#endif
|
91
91
|
|
92
|
+
/* Compiler independent macro to handle signal interrpted system calls */
|
93
|
+
#define HANDLE_EINTR(result, x) do { \
|
94
|
+
result = (x); \
|
95
|
+
} while (result == -1 && errno == EINTR);
|
96
|
+
|
97
|
+
|
92
98
|
/* Provide a 64-bit size for offsets. */
|
93
99
|
|
94
100
|
#if defined(_MSC_VER)
|
@@ -119,6 +125,9 @@ typedef int git_file;
|
|
119
125
|
extern ssize_t p_read(git_file fd, void *buf, size_t cnt);
|
120
126
|
extern int p_write(git_file fd, const void *buf, size_t cnt);
|
121
127
|
|
128
|
+
extern ssize_t p_pread(int fd, void *data, size_t size, off64_t offset);
|
129
|
+
extern ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset);
|
130
|
+
|
122
131
|
#define p_close(fd) close(fd)
|
123
132
|
#define p_umask(m) umask(m)
|
124
133
|
|
@@ -254,7 +254,8 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name)
|
|
254
254
|
if ((error = loose_parse_oid(&oid, name, &ref_file)) < 0)
|
255
255
|
goto done;
|
256
256
|
|
257
|
-
git_sortedcache_wlock(backend->refcache)
|
257
|
+
if ((error = git_sortedcache_wlock(backend->refcache)) < 0)
|
258
|
+
goto done;
|
258
259
|
|
259
260
|
if (!(error = git_sortedcache_upsert(
|
260
261
|
(void **)&ref, backend->refcache, name))) {
|
@@ -760,7 +761,8 @@ static int reference_path_available(
|
|
760
761
|
}
|
761
762
|
}
|
762
763
|
|
763
|
-
git_sortedcache_rlock(backend->refcache)
|
764
|
+
if ((error = git_sortedcache_rlock(backend->refcache)) < 0)
|
765
|
+
return error;
|
764
766
|
|
765
767
|
for (i = 0; i < git_sortedcache_entrycount(backend->refcache); ++i) {
|
766
768
|
struct packref *ref = git_sortedcache_entry(backend->refcache, i);
|
data/vendor/libgit2/src/refs.c
CHANGED
@@ -1287,19 +1287,32 @@ cleanup:
|
|
1287
1287
|
return error;
|
1288
1288
|
}
|
1289
1289
|
|
1290
|
-
int
|
1290
|
+
int git_reference__name_is_valid(
|
1291
|
+
int *valid,
|
1292
|
+
const char *refname,
|
1293
|
+
unsigned int flags)
|
1291
1294
|
{
|
1292
|
-
|
1293
|
-
git_error_clear();
|
1294
|
-
return false;
|
1295
|
-
}
|
1295
|
+
int error;
|
1296
1296
|
|
1297
|
-
|
1297
|
+
*valid = 0;
|
1298
|
+
|
1299
|
+
error = git_reference__normalize_name(NULL, refname, flags);
|
1300
|
+
|
1301
|
+
if (!error)
|
1302
|
+
*valid = 1;
|
1303
|
+
else if (error == GIT_EINVALIDSPEC)
|
1304
|
+
error = 0;
|
1305
|
+
|
1306
|
+
return error;
|
1298
1307
|
}
|
1299
1308
|
|
1300
1309
|
int git_reference_is_valid_name(const char *refname)
|
1301
1310
|
{
|
1302
|
-
|
1311
|
+
int valid = 0;
|
1312
|
+
|
1313
|
+
git_reference__name_is_valid(&valid, refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
|
1314
|
+
|
1315
|
+
return valid;
|
1303
1316
|
}
|
1304
1317
|
|
1305
1318
|
const char *git_reference__shorthand(const char *name)
|
data/vendor/libgit2/src/refs.h
CHANGED
@@ -85,7 +85,7 @@ git_reference *git_reference__realloc(git_reference **ptr_to_ref, const char *na
|
|
85
85
|
|
86
86
|
int git_reference__normalize_name(git_buf *buf, const char *name, unsigned int flags);
|
87
87
|
int git_reference__update_terminal(git_repository *repo, const char *ref_name, const git_oid *oid, const git_signature *sig, const char *log_message);
|
88
|
-
int
|
88
|
+
int git_reference__name_is_valid(int *valid, const char *name, unsigned int flags);
|
89
89
|
int git_reference__is_branch(const char *ref_name);
|
90
90
|
int git_reference__is_remote(const char *ref_name);
|
91
91
|
int git_reference__is_tag(const char *ref_name);
|
@@ -21,7 +21,8 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
|
|
21
21
|
size_t llen;
|
22
22
|
int is_glob = 0;
|
23
23
|
const char *lhs, *rhs;
|
24
|
-
int
|
24
|
+
int valid = 0;
|
25
|
+
unsigned int flags;
|
25
26
|
|
26
27
|
assert(refspec && input);
|
27
28
|
|
@@ -75,57 +76,69 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
|
|
75
76
|
|
76
77
|
if (is_fetch) {
|
77
78
|
/*
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
* LHS
|
80
|
+
* - empty is allowed; it means HEAD.
|
81
|
+
* - otherwise it must be a valid looking ref.
|
82
|
+
*/
|
82
83
|
if (!*refspec->src)
|
83
84
|
; /* empty is ok */
|
84
|
-
else if (
|
85
|
+
else if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
|
86
|
+
goto on_error;
|
87
|
+
else if (!valid)
|
85
88
|
goto invalid;
|
89
|
+
|
86
90
|
/*
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
91
|
+
* RHS
|
92
|
+
* - missing is ok, and is same as empty.
|
93
|
+
* - empty is ok; it means not to store.
|
94
|
+
* - otherwise it must be a valid looking ref.
|
95
|
+
*/
|
92
96
|
if (!refspec->dst)
|
93
97
|
; /* ok */
|
94
98
|
else if (!*refspec->dst)
|
95
99
|
; /* ok */
|
96
|
-
else if (
|
100
|
+
else if (git_reference__name_is_valid(&valid, refspec->dst, flags) < 0)
|
101
|
+
goto on_error;
|
102
|
+
else if (!valid)
|
97
103
|
goto invalid;
|
98
104
|
} else {
|
99
105
|
/*
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
+
* LHS
|
107
|
+
* - empty is allowed; it means delete.
|
108
|
+
* - when wildcarded, it must be a valid looking ref.
|
109
|
+
* - otherwise, it must be an extended SHA-1, but
|
110
|
+
* there is no existing way to validate this.
|
111
|
+
*/
|
106
112
|
if (!*refspec->src)
|
107
113
|
; /* empty is ok */
|
108
114
|
else if (is_glob) {
|
109
|
-
if (
|
115
|
+
if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
|
116
|
+
goto on_error;
|
117
|
+
else if (!valid)
|
110
118
|
goto invalid;
|
111
119
|
}
|
112
120
|
else {
|
113
121
|
; /* anything goes, for now */
|
114
122
|
}
|
123
|
+
|
115
124
|
/*
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
125
|
+
* RHS
|
126
|
+
* - missing is allowed, but LHS then must be a
|
127
|
+
* valid looking ref.
|
128
|
+
* - empty is not allowed.
|
129
|
+
* - otherwise it must be a valid looking ref.
|
130
|
+
*/
|
122
131
|
if (!refspec->dst) {
|
123
|
-
if (
|
132
|
+
if (git_reference__name_is_valid(&valid, refspec->src, flags) < 0)
|
133
|
+
goto on_error;
|
134
|
+
else if (!valid)
|
124
135
|
goto invalid;
|
125
136
|
} else if (!*refspec->dst) {
|
126
137
|
goto invalid;
|
127
138
|
} else {
|
128
|
-
if (
|
139
|
+
if (git_reference__name_is_valid(&valid, refspec->dst, flags) < 0)
|
140
|
+
goto on_error;
|
141
|
+
else if (!valid)
|
129
142
|
goto invalid;
|
130
143
|
}
|
131
144
|
|
@@ -141,11 +154,14 @@ int git_refspec__parse(git_refspec *refspec, const char *input, bool is_fetch)
|
|
141
154
|
|
142
155
|
return 0;
|
143
156
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
157
|
+
invalid:
|
158
|
+
git_error_set(GIT_ERROR_INVALID,
|
159
|
+
"'%s' is not a valid refspec.", input);
|
160
|
+
git_refspec__dispose(refspec);
|
161
|
+
return GIT_EINVALIDSPEC;
|
162
|
+
|
163
|
+
on_error:
|
164
|
+
git_refspec__dispose(refspec);
|
149
165
|
return -1;
|
150
166
|
}
|
151
167
|
|
data/vendor/libgit2/src/remote.c
CHANGED
@@ -110,12 +110,8 @@ static int write_add_refspec(git_repository *repo, const char *name, const char
|
|
110
110
|
if ((error = ensure_remote_name_is_valid(name)) < 0)
|
111
111
|
return error;
|
112
112
|
|
113
|
-
if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0)
|
114
|
-
if (git_error_last()->klass != GIT_ERROR_NOMEMORY)
|
115
|
-
error = GIT_EINVALIDSPEC;
|
116
|
-
|
113
|
+
if ((error = git_refspec__parse(&spec, refspec, fetch)) < 0)
|
117
114
|
return error;
|
118
|
-
}
|
119
115
|
|
120
116
|
git_refspec__dispose(&spec);
|
121
117
|
|
@@ -1116,7 +1112,7 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_re
|
|
1116
1112
|
git_reference *resolved_ref = NULL;
|
1117
1113
|
git_buf remote_name = GIT_BUF_INIT;
|
1118
1114
|
git_config *config = NULL;
|
1119
|
-
const char *ref_name;
|
1115
|
+
const char *ref_name = NULL;
|
1120
1116
|
int error = 0, update;
|
1121
1117
|
|
1122
1118
|
assert(out && spec && ref);
|
@@ -1129,10 +1125,20 @@ static int remote_head_for_ref(git_remote_head **out, git_remote *remote, git_re
|
|
1129
1125
|
if (error == GIT_ENOTFOUND && git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) {
|
1130
1126
|
ref_name = git_reference_symbolic_target(ref);
|
1131
1127
|
error = 0;
|
1132
|
-
} else {
|
1128
|
+
} else if (resolved_ref) {
|
1133
1129
|
ref_name = git_reference_name(resolved_ref);
|
1134
1130
|
}
|
1135
1131
|
|
1132
|
+
/*
|
1133
|
+
* The ref name may be unresolvable - perhaps it's pointing to
|
1134
|
+
* something invalid. In this case, there is no remote head for
|
1135
|
+
* this ref.
|
1136
|
+
*/
|
1137
|
+
if (!ref_name) {
|
1138
|
+
error = 0;
|
1139
|
+
goto cleanup;
|
1140
|
+
}
|
1141
|
+
|
1136
1142
|
if ((error = ref_to_update(&update, &remote_name, remote, spec, ref_name)) < 0)
|
1137
1143
|
goto cleanup;
|
1138
1144
|
|
@@ -2078,7 +2078,8 @@ static int repo_init_head(const char *repo_dir, const char *given)
|
|
2078
2078
|
if (given) {
|
2079
2079
|
initial_head = given;
|
2080
2080
|
} else if ((error = git_config_open_default(&cfg)) >= 0 &&
|
2081
|
-
(error = git_config_get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0
|
2081
|
+
(error = git_config_get_string_buf(&cfg_branch, cfg, "init.defaultbranch")) >= 0 &&
|
2082
|
+
*cfg_branch.ptr) {
|
2082
2083
|
initial_head = cfg_branch.ptr;
|
2083
2084
|
}
|
2084
2085
|
|
@@ -2334,21 +2335,19 @@ int git_repository_head_unborn(git_repository *repo)
|
|
2334
2335
|
return 0;
|
2335
2336
|
}
|
2336
2337
|
|
2337
|
-
static int at_least_one_cb(const char *refname, void *payload)
|
2338
|
-
{
|
2339
|
-
GIT_UNUSED(refname);
|
2340
|
-
GIT_UNUSED(payload);
|
2341
|
-
return GIT_PASSTHROUGH;
|
2342
|
-
}
|
2343
|
-
|
2344
2338
|
static int repo_contains_no_reference(git_repository *repo)
|
2345
2339
|
{
|
2346
|
-
|
2340
|
+
git_reference_iterator *iter;
|
2341
|
+
const char *refname;
|
2342
|
+
int error;
|
2347
2343
|
|
2348
|
-
if (error
|
2349
|
-
return
|
2344
|
+
if ((error = git_reference_iterator_new(&iter, repo)) < 0)
|
2345
|
+
return error;
|
2350
2346
|
|
2351
|
-
|
2347
|
+
error = git_reference_next_name(&refname, iter);
|
2348
|
+
git_reference_iterator_free(iter);
|
2349
|
+
|
2350
|
+
if (error == GIT_ITEROVER)
|
2352
2351
|
return 1;
|
2353
2352
|
|
2354
2353
|
return error;
|
@@ -2364,10 +2363,11 @@ int git_repository_initialbranch(git_buf *out, git_repository *repo)
|
|
2364
2363
|
if ((error = git_repository_config__weakptr(&config, repo)) < 0)
|
2365
2364
|
return error;
|
2366
2365
|
|
2367
|
-
if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0
|
2366
|
+
if ((error = git_config_get_entry(&entry, config, "init.defaultbranch")) == 0 &&
|
2367
|
+
*entry->value) {
|
2368
2368
|
branch = entry->value;
|
2369
2369
|
}
|
2370
|
-
else if (error == GIT_ENOTFOUND) {
|
2370
|
+
else if (!error || error == GIT_ENOTFOUND) {
|
2371
2371
|
branch = GIT_BRANCH_DEFAULT;
|
2372
2372
|
}
|
2373
2373
|
else {
|
@@ -2379,7 +2379,7 @@ int git_repository_initialbranch(git_buf *out, git_repository *repo)
|
|
2379
2379
|
goto done;
|
2380
2380
|
|
2381
2381
|
if (!git_reference_is_valid_name(out->ptr)) {
|
2382
|
-
git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid
|
2382
|
+
git_error_set(GIT_ERROR_INVALID, "the value of init.defaultBranch is not a valid branch name");
|
2383
2383
|
error = -1;
|
2384
2384
|
}
|
2385
2385
|
|
@@ -235,35 +235,35 @@ GIT_INLINE(int64_t) git_atomic64_get(git_atomic64 *a)
|
|
235
235
|
|
236
236
|
#else
|
237
237
|
|
238
|
+
GIT_INLINE(int) git___noop(void) { return 0; }
|
239
|
+
|
238
240
|
#define git_thread unsigned int
|
239
|
-
#define git_thread_create(thread, start_routine, arg)
|
240
|
-
#define git_thread_join(id, status) (
|
241
|
+
#define git_thread_create(thread, start_routine, arg) git___noop()
|
242
|
+
#define git_thread_join(id, status) git___noop()
|
241
243
|
|
242
244
|
/* Pthreads Mutex */
|
243
245
|
#define git_mutex unsigned int
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
#define git_mutex_unlock(a) (void)0
|
249
|
-
#define git_mutex_free(a) (void)0
|
246
|
+
#define git_mutex_init(a) git___noop()
|
247
|
+
#define git_mutex_lock(a) git___noop()
|
248
|
+
#define git_mutex_unlock(a) git___noop()
|
249
|
+
#define git_mutex_free(a) git___noop()
|
250
250
|
|
251
251
|
/* Pthreads condition vars */
|
252
252
|
#define git_cond unsigned int
|
253
|
-
#define git_cond_init(c, a) (
|
254
|
-
#define git_cond_free(c) (
|
255
|
-
#define git_cond_wait(c, l) (
|
256
|
-
#define git_cond_signal(c) (
|
257
|
-
#define git_cond_broadcast(c) (
|
253
|
+
#define git_cond_init(c, a) git___noop()
|
254
|
+
#define git_cond_free(c) git___noop()
|
255
|
+
#define git_cond_wait(c, l) git___noop()
|
256
|
+
#define git_cond_signal(c) git___noop()
|
257
|
+
#define git_cond_broadcast(c) git___noop()
|
258
258
|
|
259
259
|
/* Pthreads rwlock */
|
260
260
|
#define git_rwlock unsigned int
|
261
|
-
#define git_rwlock_init(a)
|
262
|
-
#define git_rwlock_rdlock(a)
|
263
|
-
#define git_rwlock_rdunlock(a) (
|
264
|
-
#define git_rwlock_wrlock(a)
|
265
|
-
#define git_rwlock_wrunlock(a) (
|
266
|
-
#define git_rwlock_free(a) (
|
261
|
+
#define git_rwlock_init(a) git___noop()
|
262
|
+
#define git_rwlock_rdlock(a) git___noop()
|
263
|
+
#define git_rwlock_rdunlock(a) git___noop()
|
264
|
+
#define git_rwlock_wrlock(a) git___noop()
|
265
|
+
#define git_rwlock_wrunlock(a) git___noop()
|
266
|
+
#define git_rwlock_free(a) git___noop()
|
267
267
|
#define GIT_RWLOCK_STATIC_INIT 0
|
268
268
|
|
269
269
|
|
@@ -311,6 +311,11 @@ GIT_INLINE(volatile void *) git___swap(
|
|
311
311
|
return old;
|
312
312
|
}
|
313
313
|
|
314
|
+
GIT_INLINE(volatile void *) git___load(void * volatile *ptr)
|
315
|
+
{
|
316
|
+
return *ptr;
|
317
|
+
}
|
318
|
+
|
314
319
|
#ifdef GIT_ARCH_64
|
315
320
|
|
316
321
|
GIT_INLINE(int64_t) git_atomic64_add(git_atomic64 *a, int64_t addend)
|
@@ -658,6 +658,11 @@ static int generate_connect_request(
|
|
658
658
|
return git_buf_oom(buf) ? -1 : 0;
|
659
659
|
}
|
660
660
|
|
661
|
+
static bool use_connect_proxy(git_http_client *client)
|
662
|
+
{
|
663
|
+
return client->proxy.url.host && !strcmp(client->server.url.scheme, "https");
|
664
|
+
}
|
665
|
+
|
661
666
|
static int generate_request(
|
662
667
|
git_http_client *client,
|
663
668
|
git_http_request *request)
|
@@ -713,7 +718,8 @@ static int generate_request(
|
|
713
718
|
git_buf_printf(buf, "Expect: 100-continue\r\n");
|
714
719
|
|
715
720
|
if ((error = apply_server_credentials(buf, client, request)) < 0 ||
|
716
|
-
(
|
721
|
+
(!use_connect_proxy(client) &&
|
722
|
+
(error = apply_proxy_credentials(buf, client, request)) < 0))
|
717
723
|
return error;
|
718
724
|
|
719
725
|
if (request->custom_headers) {
|
@@ -1003,8 +1009,7 @@ static int http_client_connect(
|
|
1003
1009
|
reset_parser(client);
|
1004
1010
|
|
1005
1011
|
/* Reconnect to the proxy if necessary. */
|
1006
|
-
use_proxy = client
|
1007
|
-
!strcmp(client->server.url.scheme, "https");
|
1012
|
+
use_proxy = use_connect_proxy(client);
|
1008
1013
|
|
1009
1014
|
if (use_proxy) {
|
1010
1015
|
if (!client->proxy_connected || !client->keepalive ||
|
@@ -1476,7 +1481,7 @@ int git_http_client_skip_body(git_http_client *client)
|
|
1476
1481
|
"unexpected data handled in callback");
|
1477
1482
|
error = -1;
|
1478
1483
|
}
|
1479
|
-
} while (
|
1484
|
+
} while (error >= 0 && client->state != DONE);
|
1480
1485
|
|
1481
1486
|
if (error < 0)
|
1482
1487
|
client->connected = 0;
|
@@ -53,6 +53,10 @@
|
|
53
53
|
# define WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3 0x00002000
|
54
54
|
#endif
|
55
55
|
|
56
|
+
#ifndef WINHTTP_NO_CLIENT_CERT_CONTEXT
|
57
|
+
# define WINHTTP_NO_CLIENT_CERT_CONTEXT NULL
|
58
|
+
#endif
|
59
|
+
|
56
60
|
#ifndef HTTP_STATUS_PERMANENT_REDIRECT
|
57
61
|
# define HTTP_STATUS_PERMANENT_REDIRECT 308
|
58
62
|
#endif
|
@@ -112,7 +116,8 @@ typedef struct {
|
|
112
116
|
DWORD post_body_len;
|
113
117
|
unsigned sent_request : 1,
|
114
118
|
received_response : 1,
|
115
|
-
chunked : 1
|
119
|
+
chunked : 1,
|
120
|
+
status_sending_request_reached: 1;
|
116
121
|
} winhttp_stream;
|
117
122
|
|
118
123
|
typedef struct {
|
@@ -708,30 +713,36 @@ static void CALLBACK winhttp_status(
|
|
708
713
|
DWORD status;
|
709
714
|
|
710
715
|
GIT_UNUSED(connection);
|
711
|
-
GIT_UNUSED(ctx);
|
712
716
|
GIT_UNUSED(info_len);
|
713
717
|
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
718
|
+
switch (code) {
|
719
|
+
case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
|
720
|
+
status = *((DWORD *)info);
|
721
|
+
|
722
|
+
if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
|
723
|
+
git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
|
724
|
+
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
|
725
|
+
git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
|
726
|
+
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
|
727
|
+
git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
|
728
|
+
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
|
729
|
+
git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
|
730
|
+
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
|
731
|
+
git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
|
732
|
+
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
|
733
|
+
git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
|
734
|
+
else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
|
735
|
+
git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
|
736
|
+
else
|
737
|
+
git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
|
738
|
+
|
739
|
+
break;
|
740
|
+
|
741
|
+
case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
|
742
|
+
((winhttp_stream *) ctx)->status_sending_request_reached = 1;
|
743
|
+
|
744
|
+
break;
|
745
|
+
}
|
735
746
|
}
|
736
747
|
|
737
748
|
static int winhttp_connect(
|
@@ -826,7 +837,12 @@ static int winhttp_connect(
|
|
826
837
|
goto on_error;
|
827
838
|
}
|
828
839
|
|
829
|
-
if (WinHttpSetStatusCallback(
|
840
|
+
if (WinHttpSetStatusCallback(
|
841
|
+
t->connection,
|
842
|
+
winhttp_status,
|
843
|
+
WINHTTP_CALLBACK_FLAG_SECURE_FAILURE | WINHTTP_CALLBACK_FLAG_SEND_REQUEST,
|
844
|
+
0
|
845
|
+
) == WINHTTP_INVALID_STATUS_CALLBACK) {
|
830
846
|
git_error_set(GIT_ERROR_OS, "failed to set status callback");
|
831
847
|
goto on_error;
|
832
848
|
}
|
@@ -858,12 +874,12 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
|
|
858
874
|
success = WinHttpSendRequest(s->request,
|
859
875
|
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
860
876
|
WINHTTP_NO_REQUEST_DATA, 0,
|
861
|
-
WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH,
|
877
|
+
WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH, (DWORD_PTR)s);
|
862
878
|
} else {
|
863
879
|
success = WinHttpSendRequest(s->request,
|
864
880
|
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
|
865
881
|
WINHTTP_NO_REQUEST_DATA, 0,
|
866
|
-
(DWORD)len,
|
882
|
+
(DWORD)len, (DWORD_PTR)s);
|
867
883
|
}
|
868
884
|
|
869
885
|
if (success || GetLastError() != (DWORD)SEC_E_BUFFER_TOO_SMALL)
|
@@ -875,42 +891,73 @@ static int do_send_request(winhttp_stream *s, size_t len, bool chunked)
|
|
875
891
|
|
876
892
|
static int send_request(winhttp_stream *s, size_t len, bool chunked)
|
877
893
|
{
|
878
|
-
int request_failed =
|
879
|
-
DWORD ignore_flags;
|
894
|
+
int request_failed = 1, error, attempts = 0;
|
895
|
+
DWORD ignore_flags, send_request_error;
|
880
896
|
|
881
897
|
git_error_clear();
|
882
|
-
if ((error = do_send_request(s, len, chunked)) < 0) {
|
883
|
-
if (GetLastError() != ERROR_WINHTTP_SECURE_FAILURE) {
|
884
|
-
git_error_set(GIT_ERROR_OS, "failed to send request");
|
885
|
-
return -1;
|
886
|
-
}
|
887
898
|
|
888
|
-
|
889
|
-
cert_valid =
|
890
|
-
|
899
|
+
while (request_failed && attempts++ < 3) {
|
900
|
+
int cert_valid = 1;
|
901
|
+
int client_cert_requested = 0;
|
902
|
+
request_failed = 0;
|
903
|
+
|
904
|
+
if ((error = do_send_request(s, len, chunked)) < 0) {
|
905
|
+
send_request_error = GetLastError();
|
906
|
+
request_failed = 1;
|
907
|
+
|
908
|
+
switch (send_request_error) {
|
909
|
+
case ERROR_WINHTTP_SECURE_FAILURE:
|
910
|
+
cert_valid = 0;
|
911
|
+
break;
|
912
|
+
case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
|
913
|
+
client_cert_requested = 1;
|
914
|
+
break;
|
915
|
+
default:
|
916
|
+
git_error_set(GIT_ERROR_OS, "failed to send request");
|
917
|
+
return -1;
|
918
|
+
}
|
919
|
+
}
|
891
920
|
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
921
|
+
/*
|
922
|
+
* Only check the certificate if we were able to reach the sending request phase, or
|
923
|
+
* received a secure failure error. Otherwise, the server certificate won't be available
|
924
|
+
* since the request wasn't able to complete (e.g. proxy auth required)
|
925
|
+
*/
|
926
|
+
if (!cert_valid ||
|
927
|
+
(!request_failed && s->status_sending_request_reached)) {
|
928
|
+
git_error_clear();
|
929
|
+
if ((error = certificate_check(s, cert_valid)) < 0) {
|
930
|
+
if (!git_error_last())
|
931
|
+
git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
|
896
932
|
|
897
|
-
|
898
|
-
|
933
|
+
return error;
|
934
|
+
}
|
935
|
+
}
|
899
936
|
|
900
|
-
|
901
|
-
|
902
|
-
|
937
|
+
/* if neither the request nor the certificate check returned errors, we're done */
|
938
|
+
if (!request_failed)
|
939
|
+
return 0;
|
903
940
|
|
904
|
-
|
941
|
+
if (!cert_valid) {
|
942
|
+
ignore_flags = no_check_cert_flags;
|
943
|
+
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
|
944
|
+
git_error_set(GIT_ERROR_OS, "failed to set security options");
|
945
|
+
return -1;
|
946
|
+
}
|
947
|
+
}
|
905
948
|
|
906
|
-
|
907
|
-
|
908
|
-
|
949
|
+
if (client_cert_requested) {
|
950
|
+
/*
|
951
|
+
* Client certificates are not supported, explicitly tell the server that
|
952
|
+
* (it's possible a client certificate was requested but is not required)
|
953
|
+
*/
|
954
|
+
if (!WinHttpSetOption(s->request, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)) {
|
955
|
+
git_error_set(GIT_ERROR_OS, "failed to set client cert context");
|
956
|
+
return -1;
|
957
|
+
}
|
958
|
+
}
|
909
959
|
}
|
910
960
|
|
911
|
-
if ((error = do_send_request(s, len, chunked)) < 0)
|
912
|
-
git_error_set(GIT_ERROR_OS, "failed to send request with unchecked certificate");
|
913
|
-
|
914
961
|
return error;
|
915
962
|
}
|
916
963
|
|