Commit e9cef7c4b16b2cb572ac19fcd39217f7934cfa99

Edward Thomson 2020-01-11T23:53:45

http: introduce GIT_ERROR_HTTP Disambiguate between general network problems and HTTP problems in error codes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
diff --git a/include/git2/errors.h b/include/git2/errors.h
index 4e19f89..370b6ac 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -106,7 +106,8 @@ typedef enum {
 	GIT_ERROR_FILESYSTEM,
 	GIT_ERROR_PATCH,
 	GIT_ERROR_WORKTREE,
-	GIT_ERROR_SHA1
+	GIT_ERROR_SHA1,
+	GIT_ERROR_HTTP
 } git_error_t;
 
 /**
diff --git a/src/transports/http.c b/src/transports/http.c
index 65435d1..36f038e 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -158,7 +158,7 @@ static int handle_auth(
 	}
 
 	if (error > 0) {
-		git_error_set(GIT_ERROR_NET, "%s authentication required but no callback set", server_type);
+		git_error_set(GIT_ERROR_HTTP, "%s authentication required but no callback set", server_type);
 		error = -1;
 	}
 
@@ -175,7 +175,7 @@ GIT_INLINE(int) handle_remote_auth(
 	http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
 
 	if (response->server_auth_credtypes == 0) {
-		git_error_set(GIT_ERROR_NET, "server requires authentication that we do not support");
+		git_error_set(GIT_ERROR_HTTP, "server requires authentication that we do not support");
 		return -1;
 	}
 
@@ -197,7 +197,7 @@ GIT_INLINE(int) handle_proxy_auth(
 	http_subtransport *transport = OWNING_SUBTRANSPORT(stream);
 
 	if (response->proxy_auth_credtypes == 0) {
-		git_error_set(GIT_ERROR_NET, "proxy requires authentication that we do not support");
+		git_error_set(GIT_ERROR_HTTP, "proxy requires authentication that we do not support");
 		return -1;
 	}
 
@@ -226,7 +226,7 @@ static int handle_response(
 
 	if (allow_replay && git_http_response_is_redirect(response)) {
 		if (!response->location) {
-			git_error_set(GIT_ERROR_NET, "redirect without location");
+			git_error_set(GIT_ERROR_HTTP, "redirect without location");
 			return -1;
 		}
 
@@ -236,7 +236,7 @@ static int handle_response(
 
 		return 0;
 	} else if (git_http_response_is_redirect(response)) {
-		git_error_set(GIT_ERROR_NET, "unexpected redirect");
+		git_error_set(GIT_ERROR_HTTP, "unexpected redirect");
 		return -1;
 	}
 
@@ -255,24 +255,24 @@ static int handle_response(
 		return git_http_client_skip_body(transport->http_client);
 	} else if (response->status == GIT_HTTP_STATUS_UNAUTHORIZED ||
 	           response->status == GIT_HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
-		git_error_set(GIT_ERROR_NET, "unexpected authentication failure");
+		git_error_set(GIT_ERROR_HTTP, "unexpected authentication failure");
 		return -1;
 	}
 
 	if (response->status != GIT_HTTP_STATUS_OK) {
-		git_error_set(GIT_ERROR_NET, "unexpected http status code: %d", response->status);
+		git_error_set(GIT_ERROR_HTTP, "unexpected http status code: %d", response->status);
 		return -1;
 	}
 
 	/* The response must contain a Content-Type header. */
 	if (!response->content_type) {
-		git_error_set(GIT_ERROR_NET, "no content-type header in response");
+		git_error_set(GIT_ERROR_HTTP, "no content-type header in response");
 		return -1;
 	}
 
 	/* The Content-Type header must match our expectation. */
 	if (strcmp(response->content_type, stream->service->response_type) != 0) {
-		git_error_set(GIT_ERROR_NET, "invalid content-type: '%s'", response->content_type);
+		git_error_set(GIT_ERROR_HTTP, "invalid content-type: '%s'", response->content_type);
 		return -1;
 	}
 
@@ -411,7 +411,7 @@ static int http_stream_read(
 	}
 
 	if (stream->state == HTTP_STATE_SENDING_REQUEST) {
-		git_error_set(GIT_ERROR_NET, "too many redirects or authentication replays");
+		git_error_set(GIT_ERROR_HTTP, "too many redirects or authentication replays");
 		error = -1;
 		goto done;
 	}
@@ -548,7 +548,7 @@ static int http_stream_write(
 	}
 
 	if (stream->state == HTTP_STATE_NONE) {
-		git_error_set(GIT_ERROR_NET,
+		git_error_set(GIT_ERROR_HTTP,
 		              "too many redirects or authentication replays");
 		error = -1;
 		goto done;
@@ -653,7 +653,7 @@ static int http_action(
 		return error;
 
 	if ((service = select_service(action)) == NULL) {
-		git_error_set(GIT_ERROR_NET, "invalid action");
+		git_error_set(GIT_ERROR_HTTP, "invalid action");
 		return -1;
 	}
 
diff --git a/src/transports/httpclient.c b/src/transports/httpclient.c
index b565bf5..7f44a26 100644
--- a/src/transports/httpclient.c
+++ b/src/transports/httpclient.c
@@ -154,7 +154,7 @@ static int on_header_complete(http_parser *parser)
 
 	if (!strcasecmp("Content-Type", name->ptr)) {
 		if (response->content_type) {
-			git_error_set(GIT_ERROR_NET,
+			git_error_set(GIT_ERROR_HTTP,
 			              "multiple content-type headers");
 			return -1;
 		}
@@ -166,14 +166,14 @@ static int on_header_complete(http_parser *parser)
 		int64_t len;
 
 		if (response->content_length) {
-			git_error_set(GIT_ERROR_NET,
+			git_error_set(GIT_ERROR_HTTP,
 			              "multiple content-length headers");
 			return -1;
 		}
 
 		if (git__strntol64(&len, value->ptr, value->size,
 		                   NULL, 10) < 0 || len < 0) {
-			git_error_set(GIT_ERROR_NET,
+			git_error_set(GIT_ERROR_HTTP,
 			              "invalid content-length");
 			return -1;
 		}
@@ -196,7 +196,7 @@ static int on_header_complete(http_parser *parser)
 			return -1;
 	} else if (!strcasecmp("Location", name->ptr)) {
 		if (response->location) {
-			git_error_set(GIT_ERROR_NET,
+			git_error_set(GIT_ERROR_HTTP,
 				"multiple location headers");
 			return -1;
 		}
@@ -235,7 +235,7 @@ static int on_header_field(http_parser *parser, const char *str, size_t len)
 		break;
 
 	default:
-		git_error_set(GIT_ERROR_NET,
+		git_error_set(GIT_ERROR_HTTP,
 		              "header name seen at unexpected time");
 		return ctx->parse_status = PARSE_STATUS_ERROR;
 	}
@@ -258,7 +258,7 @@ static int on_header_value(http_parser *parser, const char *str, size_t len)
 		break;
 
 	default:
-		git_error_set(GIT_ERROR_NET,
+		git_error_set(GIT_ERROR_HTTP,
 		              "header value seen at unexpected time");
 		return ctx->parse_status = PARSE_STATUS_ERROR;
 	}
@@ -348,7 +348,7 @@ static int on_headers_complete(http_parser *parser)
 		break;
 
 	default:
-		git_error_set(GIT_ERROR_NET,
+		git_error_set(GIT_ERROR_HTTP,
 		              "header completion at unexpected time");
 		return ctx->parse_status = PARSE_STATUS_ERROR;
 	}
@@ -511,14 +511,14 @@ static const char *init_auth_context(
 	int error;
 
 	if (!best_scheme_and_challenge(&scheme, &challenge, challenges, credentials)) {
-		git_error_set(GIT_ERROR_NET, "could not find appropriate mechanism for credentials");
+		git_error_set(GIT_ERROR_HTTP, "could not find appropriate mechanism for credentials");
 		return NULL;
 	}
 
 	error = scheme->init_context(&server->auth_context, &server->url);
 
 	if (error == GIT_PASSTHROUGH) {
-		git_error_set(GIT_ERROR_NET, "'%s' authentication is not supported", scheme->name);
+		git_error_set(GIT_ERROR_HTTP, "'%s' authentication is not supported", scheme->name);
 		return NULL;
 	}
 
@@ -585,7 +585,7 @@ static int apply_credentials(
 		if (auth->connection_affinity)
 			free_auth_context(server);
 	} else if (!token.size) {
-		git_error_set(GIT_ERROR_NET, "failed to respond to authentication challange");
+		git_error_set(GIT_ERROR_HTTP, "failed to respond to authentication challange");
 		error = -1;
 		goto done;
 	}
@@ -745,7 +745,7 @@ static int check_certificate(
 	else if (error == GIT_PASSTHROUGH)
 		error = 0;
 	else if (error && !git_error_last())
-		git_error_set(GIT_ERROR_NET,
+		git_error_set(GIT_ERROR_HTTP,
 		              "user rejected certificate for %s", url->host);
 
 	git_error_state_free(&last_error);
@@ -864,7 +864,7 @@ GIT_INLINE(int) server_create_stream(git_http_server *server)
 	else if (strcasecmp(url->scheme, "http") == 0)
 		return git_socket_stream_new(&server->stream, url->host, url->port);
 
-	git_error_set(GIT_ERROR_NET, "unknown http scheme '%s'", url->scheme);
+	git_error_set(GIT_ERROR_HTTP, "unknown http scheme '%s'", url->scheme);
 	return -1;
 }
 
@@ -920,7 +920,7 @@ static int proxy_connect(
 		error = GIT_RETRY;
 		goto done;
 	} else if (response.status != GIT_HTTP_STATUS_OK) {
-		git_error_set(GIT_ERROR_NET, "proxy returned unexpected status: %d", response.status);
+		git_error_set(GIT_ERROR_HTTP, "proxy returned unexpected status: %d", response.status);
 		error = -1;
 		goto done;
 	}
@@ -1044,7 +1044,7 @@ GIT_INLINE(int) client_read(git_http_client *client)
 	max_len = min(max_len, INT_MAX);
 
 	if (max_len == 0) {
-		git_error_set(GIT_ERROR_NET, "no room in output buffer");
+		git_error_set(GIT_ERROR_HTTP, "no room in output buffer");
 		return -1;
 	}
 
@@ -1101,12 +1101,12 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
 	http_errno = client->parser.http_errno;
 
 	if (parsed_len > INT_MAX) {
-		git_error_set(GIT_ERROR_NET, "unexpectedly large parse");
+		git_error_set(GIT_ERROR_HTTP, "unexpectedly large parse");
 		return -1;
 	}
 
 	if (parser->upgrade) {
-		git_error_set(GIT_ERROR_NET, "server requested upgrade");
+		git_error_set(GIT_ERROR_HTTP, "server requested upgrade");
 		return -1;
 	}
 
@@ -1140,14 +1140,14 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
 
 	/* Most failures will be reported in http_errno */
 	else if (parser->http_errno != HPE_OK) {
-		git_error_set(GIT_ERROR_NET, "http parser error: %s",
+		git_error_set(GIT_ERROR_HTTP, "http parser error: %s",
 		              http_errno_description(http_errno));
 		return -1;
 	}
 
 	/* Otherwise we should have consumed the entire buffer. */
 	else if (parsed_len != client->read_buf.size) {
-		git_error_set(GIT_ERROR_NET,
+		git_error_set(GIT_ERROR_HTTP,
 		              "http parser did not consume entire buffer: %s",
 			      http_errno_description(http_errno));
 		return -1;
@@ -1155,7 +1155,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
 
 	/* recv returned 0, the server hung up on us */
 	else if (!parsed_len) {
-		git_error_set(GIT_ERROR_NET, "unexpected EOF");
+		git_error_set(GIT_ERROR_HTTP, "unexpected EOF");
 		return -1;
 	}
 
@@ -1281,7 +1281,7 @@ int git_http_client_send_body(
 		return 0;
 
 	if (client->state != SENDING_BODY) {
-		git_error_set(GIT_ERROR_NET, "client is in invalid state");
+		git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
 		return -1;
 	}
 
@@ -1317,7 +1317,7 @@ static int complete_request(git_http_client *client)
 	assert(client && client->state == SENDING_BODY);
 
 	if (client->request_body_len && client->request_body_remain) {
-		git_error_set(GIT_ERROR_NET, "truncated write");
+		git_error_set(GIT_ERROR_HTTP, "truncated write");
 		error = -1;
 	} else if (client->request_chunked) {
 		error = stream_write(&client->server, "0\r\n\r\n", 5);
@@ -1349,7 +1349,7 @@ int git_http_client_read_response(
 	}
 
 	if (client->state != SENT_REQUEST) {
-		git_error_set(GIT_ERROR_NET, "client is in invalid state");
+		git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
 		error = -1;
 		goto done;
 	}
@@ -1392,7 +1392,7 @@ int git_http_client_read_body(
 		return 0;
 
 	if (client->state != READING_BODY) {
-		git_error_set(GIT_ERROR_NET, "client is in invalid state");
+		git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
 		return -1;
 	}
 
@@ -1438,7 +1438,7 @@ int git_http_client_skip_body(git_http_client *client)
 		return 0;
 
 	if (client->state != READING_BODY) {
-		git_error_set(GIT_ERROR_NET, "client is in invalid state");
+		git_error_set(GIT_ERROR_HTTP, "client is in invalid state");
 		return -1;
 	}
 
@@ -1451,7 +1451,7 @@ int git_http_client_skip_body(git_http_client *client)
 		if (parser_context.error != HPE_OK ||
 		    (parser_context.parse_status != PARSE_STATUS_OK &&
 		     parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) {
-			git_error_set(GIT_ERROR_NET,
+			git_error_set(GIT_ERROR_HTTP,
 			              "unexpected data handled in callback");
 			error = -1;
 		}
diff --git a/src/transports/winhttp.c b/src/transports/winhttp.c
index d8623bf..e9e53ae 100644
--- a/src/transports/winhttp.c
+++ b/src/transports/winhttp.c
@@ -145,7 +145,7 @@ static int apply_userpass_credentials(HINTERNET request, DWORD target, int mecha
 	} else if (mechanisms & GIT_WINHTTP_AUTH_BASIC) {
 		native_scheme = WINHTTP_AUTH_SCHEME_BASIC;
 	} else {
-		git_error_set(GIT_ERROR_NET, "invalid authentication scheme");
+		git_error_set(GIT_ERROR_HTTP, "invalid authentication scheme");
 		error = -1;
 		goto done;
 	}
@@ -184,7 +184,7 @@ static int apply_default_credentials(HINTERNET request, DWORD target, int mechan
 	} else if ((mechanisms & GIT_WINHTTP_AUTH_NTLM) != 0) {
 		native_scheme = WINHTTP_AUTH_SCHEME_NTLM;
 	} else {
-		git_error_set(GIT_ERROR_NET, "invalid authentication scheme");
+		git_error_set(GIT_ERROR_HTTP, "invalid authentication scheme");
 		return -1;
 	}
 
@@ -287,7 +287,7 @@ static int certificate_check(winhttp_stream *s, int valid)
 	/* If there is no override, we should fail if WinHTTP doesn't think it's fine */
 	if (t->owner->certificate_check_cb == NULL && !valid) {
 		if (!git_error_last())
-			git_error_set(GIT_ERROR_NET, "unknown certificate check failure");
+			git_error_set(GIT_ERROR_HTTP, "unknown certificate check failure");
 
 		return GIT_ECERTIFICATE;
 	}
@@ -311,7 +311,7 @@ static int certificate_check(winhttp_stream *s, int valid)
 		error = valid ? 0 : GIT_ECERTIFICATE;
 
 	if (error < 0 && !git_error_last())
-		git_error_set(GIT_ERROR_NET, "user cancelled certificate check");
+		git_error_set(GIT_ERROR_HTTP, "user cancelled certificate check");
 
 	return error;
 }
@@ -440,7 +440,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
 			goto on_error;
 
 		if (strcmp(t->proxy.url.scheme, "http") != 0 && strcmp(t->proxy.url.scheme, "https") != 0) {
-			git_error_set(GIT_ERROR_NET, "invalid URL: '%s'", proxy_url);
+			git_error_set(GIT_ERROR_HTTP, "invalid URL: '%s'", proxy_url);
 			error = -1;
 			goto on_error;
 		}
@@ -713,21 +713,21 @@ static void CALLBACK winhttp_status(
 	status = *((DWORD *)info);
 
 	if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID))
-		git_error_set(GIT_ERROR_NET, "SSL certificate issued for different common name");
+		git_error_set(GIT_ERROR_HTTP, "SSL certificate issued for different common name");
 	else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID))
-		git_error_set(GIT_ERROR_NET, "SSL certificate has expired");
+		git_error_set(GIT_ERROR_HTTP, "SSL certificate has expired");
 	else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA))
-		git_error_set(GIT_ERROR_NET, "SSL certificate signed by unknown CA");
+		git_error_set(GIT_ERROR_HTTP, "SSL certificate signed by unknown CA");
 	else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT))
-		git_error_set(GIT_ERROR_NET, "SSL certificate is invalid");
+		git_error_set(GIT_ERROR_HTTP, "SSL certificate is invalid");
 	else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED))
-		git_error_set(GIT_ERROR_NET, "certificate revocation check failed");
+		git_error_set(GIT_ERROR_HTTP, "certificate revocation check failed");
 	else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED))
-		git_error_set(GIT_ERROR_NET, "SSL certificate was revoked");
+		git_error_set(GIT_ERROR_HTTP, "SSL certificate was revoked");
 	else if ((status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR))
-		git_error_set(GIT_ERROR_NET, "security libraries could not be loaded");
+		git_error_set(GIT_ERROR_HTTP, "security libraries could not be loaded");
 	else
-		git_error_set(GIT_ERROR_NET, "unknown security error %lu", status);
+		git_error_set(GIT_ERROR_HTTP, "unknown security error %lu", status);
 }
 
 static int winhttp_connect(
@@ -971,7 +971,7 @@ static int winhttp_stream_read(
 replay:
 	/* Enforce a reasonable cap on the number of replays */
 	if (replay_count++ >= GIT_HTTP_REPLAY_MAX) {
-		git_error_set(GIT_ERROR_NET, "too many redirects or authentication replays");
+		git_error_set(GIT_ERROR_HTTP, "too many redirects or authentication replays");
 		return -1;
 	}
 
@@ -1177,7 +1177,7 @@ replay:
 		}
 
 		if (HTTP_STATUS_OK != status_code) {
-			git_error_set(GIT_ERROR_NET, "request failed with status code: %lu", status_code);
+			git_error_set(GIT_ERROR_HTTP, "request failed with status code: %lu", status_code);
 			return -1;
 		}
 
@@ -1204,7 +1204,7 @@ replay:
 		}
 
 		if (wcscmp(expected_content_type, content_type)) {
-			git_error_set(GIT_ERROR_NET, "received unexpected content-type");
+			git_error_set(GIT_ERROR_HTTP, "received unexpected content-type");
 			return -1;
 		}
 
@@ -1239,7 +1239,7 @@ static int winhttp_stream_write_single(
 
 	/* This implementation of write permits only a single call. */
 	if (s->sent_request) {
-		git_error_set(GIT_ERROR_NET, "subtransport configured for only one write");
+		git_error_set(GIT_ERROR_HTTP, "subtransport configured for only one write");
 		return -1;
 	}
 
@@ -1270,12 +1270,12 @@ static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch)
 	if (RPC_S_OK != status &&
 		RPC_S_UUID_LOCAL_ONLY != status &&
 		RPC_S_UUID_NO_ADDRESS != status) {
-		git_error_set(GIT_ERROR_NET, "unable to generate name for temp file");
+		git_error_set(GIT_ERROR_HTTP, "unable to generate name for temp file");
 		return -1;
 	}
 
 	if (buffer_len_cch < UUID_LENGTH_CCH + 1) {
-		git_error_set(GIT_ERROR_NET, "buffer too small for name of temp file");
+		git_error_set(GIT_ERROR_HTTP, "buffer too small for name of temp file");
 		return -1;
 	}