package jcifs.http;
+import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
private Map headerFields;
+ private ByteArrayOutputStream cachedOutput;
+
private String authProperty;
- private String method;
+ private String authMethod;
+
+ private boolean handshakeComplete;
static {
String domain = System.getProperty("http.auth.ntlm.domain");
public void connect() throws IOException {
if (connected) return;
- doConnect();
+ connection.connect();
connected = true;
}
+ private void handshake() throws IOException {
+ if (handshakeComplete) return;
+ doHandshake();
+ handshakeComplete = true;
+ }
+
public URL getURL() {
return connection.getURL();
}
public int getContentLength() {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getContentLength();
}
public String getContentType() {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getContentType();
}
public String getContentEncoding() {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getContentEncoding();
}
public long getExpiration() {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getExpiration();
}
public long getDate() {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getDate();
}
public long getLastModified() {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getLastModified();
}
public String getHeaderField(String header) {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getHeaderField(header);
}
- private synchronized Map getHeaderFields0() {
+ private Map getHeaderFields0() {
if (headerFields != null) return headerFields;
Map map = new HashMap();
String key = connection.getHeaderFieldKey(0);
}
public Map getHeaderFields() {
- synchronized (this) {
- if (headerFields != null) return headerFields;
- }
+ if (headerFields != null) return headerFields;
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return getHeaderFields0();
}
public int getHeaderFieldInt(String header, int def) {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getHeaderFieldInt(header, def);
}
public long getHeaderFieldDate(String header, long def) {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getHeaderFieldDate(header, def);
}
public String getHeaderFieldKey(int index) {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getHeaderFieldKey(index);
}
public String getHeaderField(int index) {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getHeaderField(index);
}
public Object getContent() throws IOException {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getContent();
}
public Object getContent(Class[] classes) throws IOException {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getContent(classes);
}
public InputStream getInputStream() throws IOException {
try {
- connect();
+ handshake();
} catch (IOException ex) { }
return connection.getInputStream();
}
try {
connect();
} catch (IOException ex) { }
- return connection.getOutputStream();
+ OutputStream output = connection.getOutputStream();
+ cachedOutput = new ByteArrayOutputStream();
+ return new CacheStream(output, cachedOutput);
}
public String toString() {
List values = new ArrayList();
values.add(value);
boolean found = false;
- synchronized (requestProperties) {
- Iterator entries = requestProperties.entrySet().iterator();
- while (entries.hasNext()) {
- Map.Entry entry = (Map.Entry) entries.next();
- if (key.equalsIgnoreCase((String) entry.getKey())) {
- entry.setValue(value);
- found = true;
- break;
- }
+ Iterator entries = requestProperties.entrySet().iterator();
+ while (entries.hasNext()) {
+ Map.Entry entry = (Map.Entry) entries.next();
+ if (key.equalsIgnoreCase((String) entry.getKey())) {
+ entry.setValue(value);
+ found = true;
+ break;
}
- if (!found) requestProperties.put(key, values);
}
+ if (!found) requestProperties.put(key, values);
connection.setRequestProperty(key, value);
}
public void addRequestProperty(String key, String value) {
if (key == null) throw new NullPointerException();
List values = null;
- synchronized (requestProperties) {
- Iterator entries = requestProperties.entrySet().iterator();
- while (entries.hasNext()) {
- Map.Entry entry = (Map.Entry) entries.next();
- if (key.equalsIgnoreCase((String) entry.getKey())) {
- values = (List) entry.getValue();
- values.add(value);
- break;
- }
- }
- if (values == null) {
- values = new ArrayList();
+ Iterator entries = requestProperties.entrySet().iterator();
+ while (entries.hasNext()) {
+ Map.Entry entry = (Map.Entry) entries.next();
+ if (key.equalsIgnoreCase((String) entry.getKey())) {
+ values = (List) entry.getValue();
values.add(value);
- requestProperties.put(key, values);
+ break;
}
}
+ if (values == null) {
+ values = new ArrayList();
+ values.add(value);
+ requestProperties.put(key, values);
+ }
// 1.3-compatible.
StringBuffer buffer = new StringBuffer();
Iterator propertyValues = values.iterator();
public Map getRequestProperties() {
Map map = new HashMap();
- synchronized (requestProperties) {
- Iterator entries = requestProperties.entrySet().iterator();
- while (entries.hasNext()) {
- Map.Entry entry = (Map.Entry) entries.next();
- map.put(entry.getKey(),
- Collections.unmodifiableList((List) entry.getValue()));
- }
+ Iterator entries = requestProperties.entrySet().iterator();
+ while (entries.hasNext()) {
+ Map.Entry entry = (Map.Entry) entries.next();
+ map.put(entry.getKey(),
+ Collections.unmodifiableList((List) entry.getValue()));
}
return Collections.unmodifiableMap(map);
}
public void setRequestMethod(String requestMethod)
throws ProtocolException {
connection.setRequestMethod(requestMethod);
+ this.method = requestMethod;
}
public String getRequestMethod() {
}
public int getResponseCode() throws IOException {
+ try {
+ handshake();
+ } catch (IOException ex) { }
return connection.getResponseCode();
}
public String getResponseMessage() throws IOException {
+ try {
+ handshake();
+ } catch (IOException ex) { }
return connection.getResponseMessage();
}
public void disconnect() {
connection.disconnect();
+ handshakeComplete = false;
connected = false;
}
}
public InputStream getErrorStream() {
+ try {
+ handshake();
+ } catch (IOException ex) { }
return connection.getErrorStream();
}
}
}
- private synchronized void doConnect() throws IOException {
- connection.connect();
- int response = parseResponseCode();
- if (response != HTTP_UNAUTHORIZED && response != HTTP_PROXY_AUTH) {
- return;
- }
- Type1Message type1 = (Type1Message) attemptNegotiation(response);
- if (type1 == null) return; // no NTLM
- int attempt = 0;
- while (attempt < MAX_REDIRECTS) {
- connection.setRequestProperty(authProperty, method + ' ' +
- Base64.encode(type1.toByteArray()));
- connection.connect(); // send type 1
- response = parseResponseCode();
+ private void doHandshake() throws IOException {
+ connect();
+ try {
+ int response = parseResponseCode();
if (response != HTTP_UNAUTHORIZED && response != HTTP_PROXY_AUTH) {
return;
}
- Type3Message type3 = (Type3Message) attemptNegotiation(response);
- if (type3 == null) return;
- connection.setRequestProperty(authProperty, method + ' ' +
- Base64.encode(type3.toByteArray()));
- connection.connect(); // send type 3
- response = parseResponseCode();
- if (response != HTTP_UNAUTHORIZED && response != HTTP_PROXY_AUTH) {
- return;
+ Type1Message type1 = (Type1Message) attemptNegotiation(response);
+ if (type1 == null) return; // no NTLM
+ int attempt = 0;
+ while (attempt < MAX_REDIRECTS) {
+ connection.setRequestProperty(authProperty, authMethod + ' ' +
+ Base64.encode(type1.toByteArray()));
+ connection.connect(); // send type 1
+ response = parseResponseCode();
+ if (response != HTTP_UNAUTHORIZED &&
+ response != HTTP_PROXY_AUTH) {
+ return;
+ }
+ Type3Message type3 = (Type3Message)
+ attemptNegotiation(response);
+ if (type3 == null) return;
+ connection.setRequestProperty(authProperty, authMethod + ' ' +
+ Base64.encode(type3.toByteArray()));
+ connection.connect(); // send type 3
+ if (cachedOutput != null && doOutput) {
+ OutputStream output = connection.getOutputStream();
+ cachedOutput.writeTo(output);
+ output.flush();
+ }
+ response = parseResponseCode();
+ if (response != HTTP_UNAUTHORIZED &&
+ response != HTTP_PROXY_AUTH) {
+ return;
+ }
+ attempt++;
+ if (allowUserInteraction && attempt < MAX_REDIRECTS) {
+ reconnect();
+ } else {
+ break;
+ }
}
- attempt++;
- if (attempt < MAX_REDIRECTS) reconnect();
+ throw new IOException("Unable to negotiate NTLM authentication.");
+ } finally {
+ cachedOutput = null;
}
- throw new IOException("Unable to negotiate NTLM authentication.");
}
private NtlmMessage attemptNegotiation(int response) throws IOException {
authProperty = null;
- method = null;
+ authMethod = null;
InputStream errorStream = connection.getErrorStream();
if (errorStream != null && errorStream.available() != 0) {
int count;
if (methods == null) return null;
Iterator iterator = methods.iterator();
while (iterator.hasNext()) {
- String authMethod = (String) iterator.next();
- if (authMethod.startsWith("NTLM")) {
- if (authMethod.length() == 4) {
- method = "NTLM";
+ String currentAuthMethod = (String) iterator.next();
+ if (currentAuthMethod.startsWith("NTLM")) {
+ if (currentAuthMethod.length() == 4) {
+ authMethod = "NTLM";
break;
}
- if (authMethod.indexOf(' ') != 4) continue;
- method = "NTLM";
- authorization = authMethod.substring(5).trim();
+ if (currentAuthMethod.indexOf(' ') != 4) continue;
+ authMethod = "NTLM";
+ authorization = currentAuthMethod.substring(5).trim();
break;
- } else if (authMethod.startsWith("Negotiate")) {
- if (authMethod.length() == 9) {
- method = "Negotiate";
+ } else if (currentAuthMethod.startsWith("Negotiate")) {
+ if (currentAuthMethod.length() == 9) {
+ authMethod = "Negotiate";
break;
}
- if (authMethod.indexOf(' ') != 9) continue;
- method = "Negotiate";
- authorization = authMethod.substring(10).trim();
+ if (currentAuthMethod.indexOf(' ') != 9) continue;
+ authMethod = "Negotiate";
+ authorization = currentAuthMethod.substring(10).trim();
break;
}
}
- if (method == null) return null;
+ if (authMethod == null) return null;
NtlmMessage message = (authorization != null) ?
new Type2Message(Base64.decode(authorization)) : null;
reconnect();
user = (index != -1) ? user.substring(index + 1) : user;
}
if (user == null) {
+ if (!allowUserInteraction) return null;
try {
URL url = getURL();
String protocol = url.getProtocol();
}
PasswordAuthentication auth =
Authenticator.requestPasswordAuthentication(null,
- port, protocol, "", method);
- if (auth != null) {
- user = auth.getUserName();
- password = new String(auth.getPassword());
- }
+ port, protocol, "", authMethod);
+ if (auth == null) return null;
+ user = auth.getUserName();
+ password = new String(auth.getPassword());
} catch (Exception ex) { }
}
Type2Message type2 = (Type2Message) message;
private void reconnect() throws IOException {
connection = (HttpURLConnection) connection.getURL().openConnection();
+ connection.setRequestMethod(method);
headerFields = null;
- synchronized (requestProperties) {
- Iterator properties = requestProperties.entrySet().iterator();
- while (properties.hasNext()) {
- Map.Entry property = (Map.Entry) properties.next();
- String key = (String) property.getKey();
- StringBuffer value = new StringBuffer();
- Iterator values = ((List) property.getValue()).iterator();
- while (values.hasNext()) {
- value.append(values.next());
- if (values.hasNext()) value.append(", ");
- }
- connection.setRequestProperty(key, value.toString());
+ Iterator properties = requestProperties.entrySet().iterator();
+ while (properties.hasNext()) {
+ Map.Entry property = (Map.Entry) properties.next();
+ String key = (String) property.getKey();
+ StringBuffer value = new StringBuffer();
+ Iterator values = ((List) property.getValue()).iterator();
+ while (values.hasNext()) {
+ value.append(values.next());
+ if (values.hasNext()) value.append(", ");
}
+ connection.setRequestProperty(key, value.toString());
}
connection.setAllowUserInteraction(allowUserInteraction);
connection.setDoInput(doInput);
connection.setIfModifiedSince(ifModifiedSince);
connection.setUseCaches(useCaches);
}
+
+ private static class CacheStream extends OutputStream {
+
+ private final OutputStream stream;
+
+ private final OutputStream collector;
+
+ public CacheStream(OutputStream stream, OutputStream collector) {
+ this.stream = stream;
+ this.collector = collector;
+ }
+
+ public void close() throws IOException {
+ stream.close();
+ collector.close();
+ }
+
+ public void flush() throws IOException {
+ stream.flush();
+ collector.flush();
+ }
+
+ public void write(byte[] b) throws IOException {
+ stream.write(b);
+ collector.write(b);
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ stream.write(b, off, len);
+ collector.write(b, off, len);
+ }
+
+ public void write(int b) throws IOException {
+ stream.write(b);
+ collector.write(b);
+ }
+
+ }
+
}