in org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java [1627:1797]
void sendRequest() throws IOException {
// Try to compress the content, but only if that is smaller.
TemporaryBuffer buf = new TemporaryBuffer.Heap(
http.getPostBuffer());
try (GZIPOutputStream gzip = new GZIPOutputStream(buf)) {
out.writeTo(gzip, null);
if (out.length() < buf.length())
buf = out;
} catch (IOException err) {
// Most likely caused by overflowing the buffer, meaning
// its larger if it were compressed. Don't compress.
buf = out;
}
HttpAuthMethod authenticator = null;
Collection<Type> ignoreTypes = EnumSet.noneOf(Type.class);
// Counts number of repeated authentication attempts using the same
// authentication scheme
int authAttempts = 1;
int redirects = 0;
for (;;) {
try {
// The very first time we will try with the authentication
// method used on the initial GET request. This is a hint
// only; it may fail. If so, we'll then re-try with proper
// 401 handling, going through the available authentication
// schemes.
openStream();
if (buf != out) {
conn.setRequestProperty(HDR_CONTENT_ENCODING,
ENCODING_GZIP);
}
conn.setFixedLengthStreamingMode((int) buf.length());
try (OutputStream httpOut = conn.getOutputStream()) {
buf.writeTo(httpOut, null);
}
final int status = HttpSupport.response(conn);
switch (status) {
case HttpConnection.HTTP_OK:
// We're done.
return;
case HttpConnection.HTTP_NOT_FOUND:
throw createNotFoundException(uri, conn.getURL(),
conn.getResponseMessage());
case HttpConnection.HTTP_FORBIDDEN:
throw new TransportException(uri,
MessageFormat.format(
JGitText.get().serviceNotPermitted,
baseUrl, serviceName));
case HttpConnection.HTTP_MOVED_PERM:
case HttpConnection.HTTP_MOVED_TEMP:
case HttpConnection.HTTP_11_MOVED_PERM:
case HttpConnection.HTTP_11_MOVED_TEMP:
// SEE_OTHER after a POST doesn't make sense for a git
// server, so we don't handle it here and thus we'll
// report an error in openResponse() later on.
if (http.getFollowRedirects() != HttpRedirectMode.TRUE) {
// Let openResponse() issue an error
return;
}
currentUri = redirect(conn.getURL(),
conn.getHeaderField(HDR_LOCATION),
'/' + serviceName, redirects++);
try {
baseUrl = toURL(currentUri);
} catch (MalformedURLException e) {
throw new TransportException(uri,
MessageFormat.format(
JGitText.get().invalidRedirectLocation,
baseUrl, currentUri),
e);
}
continue;
case HttpConnection.HTTP_UNAUTHORIZED:
HttpAuthMethod nextMethod = HttpAuthMethod
.scanResponse(conn, ignoreTypes);
switch (nextMethod.getType()) {
case NONE:
throw new TransportException(uri,
MessageFormat.format(
JGitText.get().authenticationNotSupported,
conn.getURL()));
case NEGOTIATE:
// RFC 4559 states "When using the SPNEGO [...] with
// [...] POST, the authentication should be complete
// [...] before sending the user data." So in theory
// the initial GET should have been authenticated
// already. (Unless there was a redirect?)
//
// We try this only once:
ignoreTypes.add(HttpAuthMethod.Type.NEGOTIATE);
if (authenticator != null) {
ignoreTypes.add(authenticator.getType());
}
authAttempts = 1;
// We only do the Kerberos part of SPNEGO, which
// requires only one round.
break;
default:
// DIGEST or BASIC. Let's be sure we ignore
// NEGOTIATE; if it was available, we have tried it
// before.
ignoreTypes.add(HttpAuthMethod.Type.NEGOTIATE);
if (authenticator == null || authenticator
.getType() != nextMethod.getType()) {
if (authenticator != null) {
ignoreTypes.add(authenticator.getType());
}
authAttempts = 1;
}
break;
}
authMethod = nextMethod;
authenticator = nextMethod;
CredentialsProvider credentialsProvider = getCredentialsProvider();
if (credentialsProvider == null) {
throw new TransportException(uri,
JGitText.get().noCredentialsProvider);
}
if (authAttempts > 1) {
credentialsProvider.reset(currentUri);
}
if (3 < authAttempts || !authMethod
.authorize(currentUri, credentialsProvider)) {
throw new TransportException(uri,
JGitText.get().notAuthorized);
}
authAttempts++;
continue;
default:
// Just return here; openResponse() will report an
// appropriate error.
return;
}
} catch (SSLHandshakeException e) {
handleSslFailure(e);
continue; // Re-try
} catch (SocketException | InterruptedIOException e) {
// Timeout!? Must propagate; don't try other authentication
// methods.
throw e;
} catch (IOException e) {
if (authenticator == null || authMethod
.getType() != HttpAuthMethod.Type.NONE) {
// Can happen for instance if the server advertises
// Negotiate, but the client isn't configured for
// Kerberos. The first time (authenticator == null) we
// must re-try even if the authMethod was NONE: this may
// occur if the server advertised NTLM on the GET
// and the HttpConnection managed to successfully
// authenticate under the hood with NTLM. We might not
// have picked this up on the GET's 200 response.
if (authMethod.getType() != HttpAuthMethod.Type.NONE) {
ignoreTypes.add(authMethod.getType());
}
// Start over with the remaining available methods.
authMethod = HttpAuthMethod.Type.NONE.method(null);
authenticator = authMethod;
authAttempts = 1;
continue;
}
throw e;
}
}
}