rugged 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rugged/version.rb +1 -1
  3. data/vendor/libgit2/CMakeLists.txt +1 -1
  4. data/vendor/libgit2/deps/ntlmclient/CMakeLists.txt +1 -0
  5. data/vendor/libgit2/deps/ntlmclient/compat.h +0 -34
  6. data/vendor/libgit2/deps/ntlmclient/crypt_openssl.c +1 -1
  7. data/vendor/libgit2/deps/ntlmclient/ntlm.c +5 -5
  8. data/vendor/libgit2/deps/ntlmclient/util.c +15 -1
  9. data/vendor/libgit2/deps/ntlmclient/util.h +2 -1
  10. data/vendor/libgit2/include/git2/apply.h +2 -0
  11. data/vendor/libgit2/include/git2/blob.h +17 -1
  12. data/vendor/libgit2/include/git2/common.h +5 -0
  13. data/vendor/libgit2/include/git2/config.h +1 -1
  14. data/vendor/libgit2/include/git2/diff.h +1 -1
  15. data/vendor/libgit2/include/git2/index.h +2 -2
  16. data/vendor/libgit2/include/git2/indexer.h +2 -1
  17. data/vendor/libgit2/include/git2/odb.h +15 -20
  18. data/vendor/libgit2/include/git2/refs.h +3 -3
  19. data/vendor/libgit2/include/git2/repository.h +95 -52
  20. data/vendor/libgit2/include/git2/transport.h +1 -1
  21. data/vendor/libgit2/include/git2/tree.h +2 -0
  22. data/vendor/libgit2/include/git2/version.h +2 -2
  23. data/vendor/libgit2/src/blame.c +15 -10
  24. data/vendor/libgit2/src/blob.c +9 -0
  25. data/vendor/libgit2/src/clone.c +42 -21
  26. data/vendor/libgit2/src/config_cache.c +6 -3
  27. data/vendor/libgit2/src/diff_tform.c +2 -2
  28. data/vendor/libgit2/src/index.c +6 -5
  29. data/vendor/libgit2/src/indexer.c +19 -3
  30. data/vendor/libgit2/src/integer.h +15 -0
  31. data/vendor/libgit2/src/merge.c +5 -2
  32. data/vendor/libgit2/src/mwindow.c +3 -1
  33. data/vendor/libgit2/src/odb.c +4 -3
  34. data/vendor/libgit2/src/pack.c +10 -6
  35. data/vendor/libgit2/src/posix.c +32 -9
  36. data/vendor/libgit2/src/posix.h +9 -0
  37. data/vendor/libgit2/src/refdb_fs.c +4 -2
  38. data/vendor/libgit2/src/refs.c +20 -7
  39. data/vendor/libgit2/src/refs.h +1 -1
  40. data/vendor/libgit2/src/refspec.c +48 -32
  41. data/vendor/libgit2/src/remote.c +13 -7
  42. data/vendor/libgit2/src/repository.c +15 -15
  43. data/vendor/libgit2/src/repository.h +1 -1
  44. data/vendor/libgit2/src/thread-utils.h +24 -19
  45. data/vendor/libgit2/src/transports/httpclient.c +9 -4
  46. data/vendor/libgit2/src/transports/winhttp.c +99 -52
  47. data/vendor/libgit2/src/unix/posix.h +3 -0
  48. data/vendor/libgit2/src/win32/posix_w32.c +70 -0
  49. data/vendor/libgit2/src/worktree.c +8 -1
  50. metadata +2 -2
@@ -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);
@@ -1287,19 +1287,32 @@ cleanup:
1287
1287
  return error;
1288
1288
  }
1289
1289
 
1290
- int git_reference__is_valid_name(const char *refname, unsigned int flags)
1290
+ int git_reference__name_is_valid(
1291
+ int *valid,
1292
+ const char *refname,
1293
+ unsigned int flags)
1291
1294
  {
1292
- if (git_reference__normalize_name(NULL, refname, flags) < 0) {
1293
- git_error_clear();
1294
- return false;
1295
- }
1295
+ int error;
1296
1296
 
1297
- return true;
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
- return git_reference__is_valid_name(refname, GIT_REFERENCE_FORMAT_ALLOW_ONELEVEL);
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)
@@ -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 git_reference__is_valid_name(const char *refname, unsigned int flags);
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 flags;
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
- * LHS
79
- * - empty is allowed; it means HEAD.
80
- * - otherwise it must be a valid looking ref.
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 (!git_reference__is_valid_name(refspec->src, flags))
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
- * RHS
88
- * - missing is ok, and is same as empty.
89
- * - empty is ok; it means not to store.
90
- * - otherwise it must be a valid looking ref.
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 (!git_reference__is_valid_name(refspec->dst, flags))
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
- * LHS
101
- * - empty is allowed; it means delete.
102
- * - when wildcarded, it must be a valid looking ref.
103
- * - otherwise, it must be an extended SHA-1, but
104
- * there is no existing way to validate this.
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 (!git_reference__is_valid_name(refspec->src, flags))
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
- * RHS
117
- * - missing is allowed, but LHS then must be a
118
- * valid looking ref.
119
- * - empty is not allowed.
120
- * - otherwise it must be a valid looking ref.
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 (!git_reference__is_valid_name(refspec->src, flags))
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 (!git_reference__is_valid_name(refspec->dst, flags))
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
- invalid:
145
- git_error_set(
146
- GIT_ERROR_INVALID,
147
- "'%s' is not a valid refspec.", input);
148
- git_refspec__dispose(refspec);
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
 
@@ -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
- int error = git_reference_foreach_name(repo, &at_least_one_cb, NULL);
2340
+ git_reference_iterator *iter;
2341
+ const char *refname;
2342
+ int error;
2347
2343
 
2348
- if (error == GIT_PASSTHROUGH)
2349
- return 0;
2344
+ if ((error = git_reference_iterator_new(&iter, repo)) < 0)
2345
+ return error;
2350
2346
 
2351
- if (!error)
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 reference name");
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
 
@@ -154,7 +154,7 @@ struct git_repository {
154
154
 
155
155
  git_atomic attr_session_key;
156
156
 
157
- git_configmap_value configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
157
+ intptr_t configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
158
158
  git_strmap *submodule_cache;
159
159
  };
160
160
 
@@ -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) 0
240
- #define git_thread_join(id, status) (void)0
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
- GIT_INLINE(int) git_mutex_init(git_mutex *mutex) \
245
- { GIT_UNUSED(mutex); return 0; }
246
- GIT_INLINE(int) git_mutex_lock(git_mutex *mutex) \
247
- { GIT_UNUSED(mutex); return 0; }
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) (void)0
254
- #define git_cond_free(c) (void)0
255
- #define git_cond_wait(c, l) (void)0
256
- #define git_cond_signal(c) (void)0
257
- #define git_cond_broadcast(c) (void)0
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) 0
262
- #define git_rwlock_rdlock(a) 0
263
- #define git_rwlock_rdunlock(a) (void)0
264
- #define git_rwlock_wrlock(a) 0
265
- #define git_rwlock_wrunlock(a) (void)0
266
- #define git_rwlock_free(a) (void)0
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
- (error = apply_proxy_credentials(buf, client, request)) < 0)
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->proxy.url.host &&
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 (!error);
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
- if (code != WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
715
- return;
716
-
717
- status = *((DWORD *)info);
718
-
719
- if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
720
- git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
721
- else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
722
- git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
723
- else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
724
- git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
725
- else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
726
- git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
727
- else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
728
- git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
729
- else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
730
- git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
731
- else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
732
- git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
733
- else
734
- git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
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(t->connection, winhttp_status, WINHTTP_CALLBACK_FLAG_SECURE_FAILURE, 0) == WINHTTP_INVALID_STATUS_CALLBACK) {
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, 0);
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, 0);
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 = 0, cert_valid = 1, error = 0;
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
- request_failed = 1;
889
- cert_valid = 0;
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
- git_error_clear();
893
- if ((error = certificate_check(s, cert_valid)) < 0) {
894
- if (!git_error_last())
895
- git_error_set(GIT_ERROR_OS, "user cancelled certificate check");
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
- return error;
898
- }
933
+ return error;
934
+ }
935
+ }
899
936
 
900
- /* if neither the request nor the certificate check returned errors, we're done */
901
- if (!request_failed)
902
- return 0;
937
+ /* if neither the request nor the certificate check returned errors, we're done */
938
+ if (!request_failed)
939
+ return 0;
903
940
 
904
- ignore_flags = no_check_cert_flags;
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
- if (!WinHttpSetOption(s->request, WINHTTP_OPTION_SECURITY_FLAGS, &ignore_flags, sizeof(ignore_flags))) {
907
- git_error_set(GIT_ERROR_OS, "failed to set security options");
908
- return -1;
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