asyncHandler, Semaphore available) {
- this.asyncHandler = asyncHandler;
- this.available = available;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onThrowable(Throwable t) {
- try {
- asyncHandler.onThrowable(t);
- } finally {
- available.release();
- if (logger.isDebugEnabled()) {
- logger.debug("Current Throttling Status after onThrowable {}", available.availablePermits());
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception {
- return asyncHandler.onBodyPartReceived(bodyPart);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception {
- return asyncHandler.onStatusReceived(responseStatus);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception {
- return asyncHandler.onHeadersReceived(headers);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public T onCompleted() throws Exception {
- available.release();
- if (logger.isDebugEnabled()) {
- logger.debug("Current Throttling Status {}", available.availablePermits());
- }
- return asyncHandler.onCompleted();
- }
-}
\ No newline at end of file
diff --git a/api/src/main/java/org/asynchttpclient/filter/FilterException.java b/api/src/main/java/org/asynchttpclient/filter/FilterException.java
deleted file mode 100644
index 739ecf7748..0000000000
--- a/api/src/main/java/org/asynchttpclient/filter/FilterException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.filter;
-
-/**
- * An exception that can be thrown by an {@link org.asynchttpclient.AsyncHandler} to interrupt invocation of
- * the {@link RequestFilter} and {@link ResponseFilter}. It also interrupt the request and response processing.
- */
-@SuppressWarnings("serial")
-public class FilterException extends Exception {
-
- /**
- * @param message
- */
- public FilterException(final String message) {
- super(message);
- }
-
- /**
- * @param message
- * @param cause
- */
- public FilterException(final String message, final Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java b/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java
deleted file mode 100644
index 007a993206..0000000000
--- a/api/src/main/java/org/asynchttpclient/generators/FileBodyGenerator.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.generators;
-
-import org.asynchttpclient.BodyGenerator;
-import org.asynchttpclient.RandomAccessBody;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.channels.WritableByteChannel;
-
-/**
- * Creates a request body from the contents of a file.
- */
-public class FileBodyGenerator implements BodyGenerator {
-
- private final File file;
- private final long regionSeek;
- private final long regionLength;
-
- public FileBodyGenerator(File file) {
- this(file, 0L, file.length());
- }
-
- public FileBodyGenerator(File file, long regionSeek, long regionLength) {
- if (file == null) {
- throw new NullPointerException("file");
- }
- this.file = file;
- this.regionLength = regionLength;
- this.regionSeek = regionSeek;
- }
-
- public File getFile() {
- return file;
- }
-
- public long getRegionLength() {
- return regionLength;
- }
-
- public long getRegionSeek() {
- return regionSeek;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public RandomAccessBody createBody() throws IOException {
- return new FileBody(file, regionSeek, regionLength);
- }
-
- private static class FileBody implements RandomAccessBody {
-
- private final RandomAccessFile raf;
-
- private final FileChannel channel;
-
- private final long length;
-
- private FileBody(File file, long regionSeek, long regionLength) throws IOException {
- raf = new RandomAccessFile(file, "r");
- channel = raf.getChannel();
- length = regionLength;
- if (regionSeek > 0) {
- raf.seek(regionSeek);
- }
- }
-
- public long getContentLength() {
- return length;
- }
-
- public long read(ByteBuffer buffer) throws IOException {
- return channel.read(buffer);
- }
-
- public long transferTo(long position, long count, WritableByteChannel target) throws IOException {
- if (count > length) {
- count = length;
- }
- return channel.transferTo(position, count, target);
- }
-
- public void close() throws IOException {
- raf.close();
- }
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/listenable/AbstractListenableFuture.java b/api/src/main/java/org/asynchttpclient/listenable/AbstractListenableFuture.java
deleted file mode 100644
index be0d81842f..0000000000
--- a/api/src/main/java/org/asynchttpclient/listenable/AbstractListenableFuture.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-/*
- * Copyright (C) 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.asynchttpclient.listenable;
-
-import org.asynchttpclient.ListenableFuture;
-
-import java.util.concurrent.Executor;
-
-/**
- * An abstract base implementation of the listener support provided by
- * {@link ListenableFuture}. This class uses an {@link ExecutionList} to
- * guarantee that all registered listeners will be executed. Listener/Executor
- * pairs are stored in the execution list and executed in the order in which
- * they were added, but because of thread scheduling issues there is no
- * guarantee that the JVM will execute them in order. In addition, listeners
- * added after the task is complete will be executed immediately, even if some
- * previously added listeners have not yet been executed.
- *
- * @author Sven Mawson
- * @since 1
- */
-public abstract class AbstractListenableFuture implements ListenableFuture {
-
- // The execution list to hold our executors.
- private final ExecutionList executionList = new ExecutionList();
-
- /*
- * Adds a listener/executor pair to execution list to execute when this task
- * is completed.
- */
-
- public ListenableFuture addListener(Runnable listener, Executor exec) {
- executionList.add(listener, exec);
- return this;
- }
-
- /*
- * Execute the execution list.
- */
- protected void runListeners() {
- executionList.run();
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/listenable/ExecutionList.java b/api/src/main/java/org/asynchttpclient/listenable/ExecutionList.java
deleted file mode 100644
index 99347e792f..0000000000
--- a/api/src/main/java/org/asynchttpclient/listenable/ExecutionList.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-/*
- * Copyright (C) 2007 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.asynchttpclient.listenable;
-
-import java.util.Queue;
-import java.util.concurrent.Executor;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * A list of ({@code Runnable}, {@code Executor}) pairs that guarantees
- * that every {@code Runnable} that is added using the add method will be
- * executed in its associated {@code Executor} after {@link #run()} is called.
- * {@code Runnable}s added after {@code run} is called are still guaranteed to
- * execute.
- *
- * @author Nishant Thakkar
- * @author Sven Mawson
- * @since 1
- */
-public final class ExecutionList implements Runnable {
-
- // Logger to log exceptions caught when running runnables.
- private static final Logger log = Logger.getLogger(ExecutionList.class.getName());
-
- // The runnable,executor pairs to execute.
- private final Queue runnables = new LinkedBlockingQueue();
-
- // Boolean we use mark when execution has started. Only accessed from within
- // synchronized blocks.
- private boolean executed = false;
-
- /**
- * Add the runnable/executor pair to the list of pairs to execute. Executes
- * the pair immediately if we've already started execution.
- */
- public void add(Runnable runnable, Executor executor) {
-
- if (runnable == null) {
- throw new NullPointerException("Runnable is null");
- }
-
- if (executor == null) {
- throw new NullPointerException("Executor is null");
- }
-
- boolean executeImmediate = false;
-
- // Lock while we check state. We must maintain the lock while adding the
- // new pair so that another thread can't run the list out from under us.
- // We only add to the list if we have not yet started execution.
- synchronized (runnables) {
- if (!executed) {
- runnables.add(new RunnableExecutorPair(runnable, executor));
- } else {
- executeImmediate = true;
- }
- }
-
- // Execute the runnable immediately. Because of scheduling this may end up
- // getting called before some of the previously added runnables, but we're
- // ok with that. If we want to change the contract to guarantee ordering
- // among runnables we'd have to modify the logic here to allow it.
- if (executeImmediate) {
- executor.execute(runnable);
- }
- }
-
- /**
- * Runs this execution list, executing all pairs in the order they were
- * added. Pairs added after this method has started executing the list will
- * be executed immediately.
- */
- public void run() {
-
- // Lock while we update our state so the add method above will finish adding
- // any listeners before we start to run them.
- synchronized (runnables) {
- executed = true;
- }
-
- // At this point the runnables will never be modified by another
- // thread, so we are safe using it outside of the synchronized block.
- while (!runnables.isEmpty()) {
- runnables.poll().execute();
- }
- }
-
- private static class RunnableExecutorPair {
- final Runnable runnable;
- final Executor executor;
-
- RunnableExecutorPair(Runnable runnable, Executor executor) {
- this.runnable = runnable;
- this.executor = executor;
- }
-
- void execute() {
- try {
- executor.execute(runnable);
- } catch (RuntimeException e) {
- // Log it and keep going, bad runnable and/or executor. Don't
- // punish the other runnables if we're given a bad one. We only
- // catch RuntimeException because we want Errors to propagate up.
- log.log(Level.SEVERE, "RuntimeException while executing runnable " + runnable + " with executor " + executor, e);
- }
- }
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java b/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java
deleted file mode 100644
index 14edabbd52..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/AbstractFilePart.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import org.asynchttpclient.util.StandardCharsets;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * This class is an adaptation of the Apache HttpClient implementation
- *
- * @link http://hc.apache.org/httpclient-3.x/
- */
-public abstract class AbstractFilePart extends PartBase {
-
- /**
- * Default content encoding of file attachments.
- */
- public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
-
- /**
- * Default charset of file attachments.
- */
- public static final String DEFAULT_CHARSET = StandardCharsets.ISO_8859_1.name();
-
- /**
- * Default transfer encoding of file attachments.
- */
- public static final String DEFAULT_TRANSFER_ENCODING = "binary";
-
- /**
- * Attachment's file name as a byte array
- */
- private static final byte[] FILE_NAME_BYTES = "; filename=".getBytes(StandardCharsets.US_ASCII);
-
- private long stalledTime = -1L;
-
- /**
- * FilePart Constructor.
- *
- * @param name
- * the name for this part
- * @param partSource
- * the source for this part
- * @param contentType
- * the content type for this part, if null
the {@link #DEFAULT_CONTENT_TYPE default} is used
- * @param charset
- * the charset encoding for this part, if null
the {@link #DEFAULT_CHARSET default} is used
- * @param contentId
- */
- public AbstractFilePart(String name, String contentType, String charset, String contentId) {
- super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset == null ? DEFAULT_CHARSET : charset,
- DEFAULT_TRANSFER_ENCODING, contentId);
- }
-
- public abstract String getFileName();
-
- protected void visitDispositionHeader(PartVisitor visitor) throws IOException {
- super.visitDispositionHeader(visitor);
- String filename = getFileName();
- if (filename != null) {
- visitor.withBytes(FILE_NAME_BYTES);
- visitor.withBytes(QUOTE_BYTES);
- visitor.withBytes(filename.getBytes(StandardCharsets.US_ASCII));
- visitor.withBytes(QUOTE_BYTES);
- }
- }
-
- public void setStalledTime(long ms) {
- stalledTime = ms;
- }
-
- public long getStalledTime() {
- return stalledTime;
- }
-
- protected byte[] generateFileStart(byte[] boundary) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out);
- visitStart(visitor, boundary);
- visitDispositionHeader(visitor);
- visitContentTypeHeader(visitor);
- visitTransferEncodingHeader(visitor);
- visitContentIdHeader(visitor);
- visitEndOfHeader(visitor);
-
- return out.toByteArray();
- }
-
- protected byte[] generateFileEnd() throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out);
- visitEnd(visitor);
- return out.toByteArray();
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java b/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java
deleted file mode 100644
index 0dc115be98..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/ByteArrayPart.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.channels.WritableByteChannel;
-
-public class ByteArrayPart extends AbstractFilePart {
-
- private final byte[] bytes;
- private final String fileName;
-
- public ByteArrayPart(String name, byte[] bytes) {
- this(name, bytes, null);
- }
-
- public ByteArrayPart(String name, byte[] bytes, String contentType) {
- this(name, bytes, contentType, null);
- }
-
- public ByteArrayPart(String name, byte[] bytes, String contentType, String charset) {
- this(name, bytes, contentType, charset, null);
- }
-
- public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName) {
- this(name, bytes, contentType, charset, fileName, null);
- }
-
- public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId) {
- super(name, contentType, charset, contentId);
- if (bytes == null) {
- throw new NullPointerException("bytes");
- }
- this.bytes = bytes;
- this.fileName = fileName;
- }
-
- @Override
- public String getFileName() {
- return fileName;
- }
-
- @Override
- protected void sendData(OutputStream out) throws IOException {
- out.write(bytes);
- }
-
- @Override
- protected long getDataLength() {
- return bytes.length;
- }
-
- public byte[] getBytes() {
- return bytes;
- }
-
- @Override
- public long write(WritableByteChannel target, byte[] boundary) throws IOException {
- FilePartStallHandler handler = new FilePartStallHandler(getStalledTime(), this);
-
- try {
- handler.start();
-
- long length = MultipartUtils.writeBytesToChannel(target, generateFileStart(boundary));
- length += MultipartUtils.writeBytesToChannel(target, bytes);
- length += MultipartUtils.writeBytesToChannel(target, generateFileEnd());
-
- return length;
- } finally {
- handler.completed();
- }
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java
deleted file mode 100644
index 738db27144..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/CounterPartVisitor.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import java.io.IOException;
-
-public class CounterPartVisitor implements PartVisitor {
-
- private long count = 0L;
-
- @Override
- public void withBytes(byte[] bytes) throws IOException {
- count += bytes.length;
- }
-
- public long getCount() {
- return count;
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java b/api/src/main/java/org/asynchttpclient/multipart/FilePart.java
deleted file mode 100644
index b05802807d..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/FilePart.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.nio.channels.FileChannel;
-import java.nio.channels.WritableByteChannel;
-
-public class FilePart extends AbstractFilePart {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(FilePart.class);
-
- private final File file;
- private final String fileName;
-
- public FilePart(String name, File file) {
- this(name, file, null, null);
- }
-
- public FilePart(String name, File file, String contentType) {
- this(name, file, null, contentType, null);
- }
-
- public FilePart(String name, File file, String contentType, String charset) {
- this(name, file, null, contentType, charset, null);
- }
-
- public FilePart(String name, File file, String contentType, String charset, String fileName) {
- this(name, file, null, contentType, charset, fileName);
- }
-
- public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId) {
- super(name, contentType, charset, contentId);
- this.file = file;
- if (file == null) {
- throw new NullPointerException("file");
- }
- if (!file.isFile()) {
- throw new IllegalArgumentException("File is not a normal file " + file.getAbsolutePath());
- }
- if (!file.canRead()) {
- throw new IllegalArgumentException("File is not readable " + file.getAbsolutePath());
- }
- this.fileName = fileName != null ? fileName : file.getName();
- }
-
- @Override
- public String getFileName() {
- return fileName;
- }
-
- @Override
- protected void sendData(OutputStream out) throws IOException {
- if (getDataLength() == 0) {
-
- // this file contains no data, so there is nothing to send.
- // we don't want to create a zero length buffer as this will
- // cause an infinite loop when reading.
- return;
- }
-
- byte[] tmp = new byte[4096];
- InputStream instream = new FileInputStream(file);
- try {
- int len;
- while ((len = instream.read(tmp)) >= 0) {
- out.write(tmp, 0, len);
- }
- } finally {
- // we're done with the stream, close it
- instream.close();
- }
- }
-
- @Override
- protected long getDataLength() {
- return file.length();
- }
-
- public File getFile() {
- return file;
- }
-
- @Override
- public long write(WritableByteChannel target, byte[] boundary) throws IOException {
- FilePartStallHandler handler = new FilePartStallHandler(getStalledTime(), this);
-
- handler.start();
-
- int length = 0;
-
- length += MultipartUtils.writeBytesToChannel(target, generateFileStart(boundary));
-
- RandomAccessFile raf = new RandomAccessFile(file, "r");
- FileChannel fc = raf.getChannel();
-
- long l = file.length();
- int fileLength = 0;
- long nWrite = 0;
- // FIXME why sync?
- try {
- synchronized (fc) {
- while (fileLength != l) {
- if (handler.isFailed()) {
- LOGGER.debug("Stalled error");
- throw new FileUploadStalledException();
- }
- try {
- nWrite = fc.transferTo(fileLength, l, target);
-
- if (nWrite == 0) {
- LOGGER.info("Waiting for writing...");
- try {
- fc.wait(50);
- } catch (InterruptedException e) {
- LOGGER.trace(e.getMessage(), e);
- }
- } else {
- handler.writeHappened();
- }
- } catch (IOException ex) {
- String message = ex.getMessage();
-
- // http://bugs.sun.com/view_bug.do?bug_id=5103988
- if (message != null && message.equalsIgnoreCase("Resource temporarily unavailable")) {
- try {
- fc.wait(1000);
- } catch (InterruptedException e) {
- LOGGER.trace(e.getMessage(), e);
- }
- LOGGER.warn("Experiencing NIO issue http://bugs.sun.com/view_bug.do?bug_id=5103988. Retrying");
- continue;
- } else {
- throw ex;
- }
- }
- fileLength += nWrite;
- }
- }
- } finally {
- handler.completed();
- raf.close();
- }
-
- length += MultipartUtils.writeBytesToChannel(target, generateFileEnd());
-
- return length;
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/FilePartStallHandler.java b/api/src/main/java/org/asynchttpclient/multipart/FilePartStallHandler.java
deleted file mode 100644
index ed89723027..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/FilePartStallHandler.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.multipart;
-
-import java.util.Timer;
-import java.util.TimerTask;
-
-/**
- * @author Gail Hernandez
- */
-public class FilePartStallHandler extends TimerTask {
- public FilePartStallHandler(long waitTime, AbstractFilePart filePart) {
- _waitTime = waitTime;
- _failed = false;
- _written = false;
- }
-
- public void completed() {
- if (_waitTime > 0) {
- _timer.cancel();
- }
- }
-
- public boolean isFailed() {
- return _failed;
- }
-
- public void run() {
- if (!_written) {
- _failed = true;
- _timer.cancel();
- }
- _written = false;
- }
-
- public void start() {
- if (_waitTime > 0) {
- _timer = new Timer();
- _timer.scheduleAtFixedRate(this, _waitTime, _waitTime);
- }
- }
-
- public void writeHappened() {
- _written = true;
- }
-
- private long _waitTime;
- private Timer _timer;
- private boolean _failed;
- private boolean _written;
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/FileUploadStalledException.java b/api/src/main/java/org/asynchttpclient/multipart/FileUploadStalledException.java
deleted file mode 100644
index 031f9354a7..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/FileUploadStalledException.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
-* Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
-*
-* This program is licensed to you under the Apache License Version 2.0,
-* and you may not use this file except in compliance with the Apache License Version 2.0.
-* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the Apache License Version 2.0 is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
-*/
-package org.asynchttpclient.multipart;
-
-import java.io.IOException;
-
-/**
- * @author Gail Hernandez
- */
-@SuppressWarnings("serial")
-public class FileUploadStalledException extends IOException {
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java
deleted file mode 100644
index 1515409364..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/MultipartBody.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.multipart;
-
-import org.asynchttpclient.RandomAccessBody;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.channels.WritableByteChannel;
-import java.util.ArrayList;
-import java.util.List;
-
-public class MultipartBody implements RandomAccessBody {
-
- private final static Logger LOGGER = LoggerFactory.getLogger(MultipartBody.class);
-
- private final byte[] boundary;
- private final long contentLength;
- private final String contentType;
- private final List parts;
- private final List pendingOpenFiles = new ArrayList();
-
- private boolean transfertDone = false;
-
- private int currentPart = 0;
- private byte[] currentBytes;
- private int currentBytesPosition = -1;
- private boolean doneWritingParts = false;
- private FileLocation fileLocation = FileLocation.NONE;
- private FileChannel currentFileChannel;
-
- enum FileLocation {
- NONE, START, MIDDLE, END
- }
-
- public MultipartBody(List parts, String contentType, long contentLength, byte[] boundary) {
- this.boundary = boundary;
- this.contentLength = contentLength;
- this.contentType = contentType;
- this.parts = parts;
- }
-
- public void close() throws IOException {
- for (RandomAccessFile file : pendingOpenFiles) {
- file.close();
- }
- }
-
- public long getContentLength() {
- return contentLength;
- }
-
- public String getContentType() {
- return contentType;
- }
-
- // RandomAccessBody API, suited for HTTP but not for HTTPS
- public long transferTo(long position, long count, WritableByteChannel target) throws IOException {
-
- long overallLength = 0;
-
- if (transfertDone) {
- return contentLength;
- }
-
- for (Part part : parts) {
- overallLength += part.write(target, boundary);
- }
-
- overallLength += MultipartUtils.writeBytesToChannel(target, MultipartUtils.getMessageEnd(boundary));
-
- transfertDone = true;
-
- return overallLength;
- }
-
- // Regular Body API
- public long read(ByteBuffer buffer) throws IOException {
- try {
- int overallLength = 0;
-
- int maxLength = buffer.remaining();
-
- if (currentPart == parts.size() && transfertDone) {
- return -1;
- }
-
- boolean full = false;
-
- while (!full && !doneWritingParts) {
- Part part = null;
-
- if (currentPart < parts.size()) {
- part = parts.get(currentPart);
- }
- if (currentFileChannel != null) {
- overallLength += writeCurrentFile(buffer);
- full = overallLength == maxLength;
-
- } else if (currentBytesPosition > -1) {
- overallLength += writeCurrentBytes(buffer, maxLength - overallLength);
- full = overallLength == maxLength;
-
- if (currentPart == parts.size() && currentBytesFullyRead()) {
- doneWritingParts = true;
- }
-
- } else if (part instanceof StringPart) {
- StringPart stringPart = (StringPart) part;
- // set new bytes, not full, so will loop to writeCurrentBytes above
- initializeCurrentBytes(stringPart.getBytes(boundary));
- currentPart++;
-
- } else if (part instanceof AbstractFilePart) {
-
- AbstractFilePart filePart = (AbstractFilePart) part;
-
- switch (fileLocation) {
- case NONE:
- // set new bytes, not full, so will loop to writeCurrentBytes above
- initializeCurrentBytes(filePart.generateFileStart(boundary));
- fileLocation = FileLocation.START;
- break;
- case START:
- // set current file channel so code above executes first
- initializeFileBody(filePart);
- fileLocation = FileLocation.MIDDLE;
- break;
- case MIDDLE:
- initializeCurrentBytes(filePart.generateFileEnd());
- fileLocation = FileLocation.END;
- break;
- case END:
- currentPart++;
- fileLocation = FileLocation.NONE;
- if (currentPart == parts.size()) {
- doneWritingParts = true;
- }
- }
- }
- }
-
- if (doneWritingParts) {
- if (currentBytesPosition == -1) {
- initializeCurrentBytes(MultipartUtils.getMessageEnd(boundary));
- }
-
- if (currentBytesPosition > -1) {
- overallLength += writeCurrentBytes(buffer, maxLength - overallLength);
-
- if (currentBytesFullyRead()) {
- currentBytes = null;
- currentBytesPosition = -1;
- transfertDone = true;
- }
- }
- }
- return overallLength;
-
- } catch (Exception e) {
- LOGGER.error("Read exception", e);
- return 0;
- }
- }
-
- private boolean currentBytesFullyRead() {
- return currentBytes == null || currentBytesPosition >= currentBytes.length - 1;
- }
-
- private void initializeFileBody(AbstractFilePart part) throws IOException {
-
- if (part instanceof FilePart) {
- RandomAccessFile raf = new RandomAccessFile(FilePart.class.cast(part).getFile(), "r");
- pendingOpenFiles.add(raf);
- currentFileChannel = raf.getChannel();
-
- } else if (part instanceof ByteArrayPart) {
- initializeCurrentBytes(ByteArrayPart.class.cast(part).getBytes());
-
- } else {
- throw new IllegalArgumentException("Unknow AbstractFilePart type");
- }
- }
-
- private void initializeCurrentBytes(byte[] bytes) throws IOException {
- currentBytes = bytes;
- currentBytesPosition = 0;
- }
-
- private int writeCurrentFile(ByteBuffer buffer) throws IOException {
-
- int read = currentFileChannel.read(buffer);
-
- if (currentFileChannel.position() == currentFileChannel.size()) {
-
- currentFileChannel.close();
- currentFileChannel = null;
-
- int currentFile = pendingOpenFiles.size() - 1;
- pendingOpenFiles.get(currentFile).close();
- pendingOpenFiles.remove(currentFile);
- }
-
- return read;
- }
-
- private int writeCurrentBytes(ByteBuffer buffer, int length) throws IOException {
-
- int available = currentBytes.length - currentBytesPosition;
-
- int writeLength = Math.min(available, length);
-
- if (writeLength > 0) {
- buffer.put(currentBytes, currentBytesPosition, writeLength);
-
- if (available <= length) {
- currentBytesPosition = -1;
- currentBytes = null;
- } else {
- currentBytesPosition += writeLength;
- }
- }
-
- return writeLength;
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java b/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java
deleted file mode 100644
index e73cb802a6..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/MultipartUtils.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import static org.asynchttpclient.multipart.Part.CRLF_BYTES;
-import static org.asynchttpclient.multipart.Part.EXTRA_BYTES;
-import static org.asynchttpclient.util.MiscUtil.isNonEmpty;
-
-import org.asynchttpclient.FluentCaseInsensitiveStringsMap;
-import org.asynchttpclient.util.StandardCharsets;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.SelectionKey;
-import java.nio.channels.Selector;
-import java.nio.channels.SocketChannel;
-import java.nio.channels.WritableByteChannel;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-
-public class MultipartUtils {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(MultipartUtils.class);
-
- /**
- * The Content-Type for multipart/form-data.
- */
- private static final String MULTIPART_FORM_CONTENT_TYPE = "multipart/form-data";
-
- /**
- * The pool of ASCII chars to be used for generating a multipart boundary.
- */
- private static byte[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
- .getBytes(StandardCharsets.US_ASCII);
-
- private MultipartUtils() {
- }
-
- /**
- * Creates a new multipart entity containing the given parts.
- *
- * @param parts
- * The parts to include.
- */
- public static MultipartBody newMultipartBody(List parts, FluentCaseInsensitiveStringsMap requestHeaders) {
- if (parts == null) {
- throw new IllegalArgumentException("parts cannot be null");
- }
-
- byte[] multipartBoundary;
- String contentType;
-
- String contentTypeHeader = requestHeaders.getFirstValue("Content-Type");
- if (isNonEmpty(contentTypeHeader)) {
- int boundaryLocation = contentTypeHeader.indexOf("boundary=");
- if (boundaryLocation != -1) {
- // boundary defined in existing Content-Type
- contentType = contentTypeHeader;
- multipartBoundary = (contentTypeHeader.substring(boundaryLocation + "boundary=".length()).trim())
- .getBytes(StandardCharsets.US_ASCII);
- } else {
- // generate boundary and append it to existing Content-Type
- multipartBoundary = generateMultipartBoundary();
- contentType = computeContentType(contentTypeHeader, multipartBoundary);
- }
- } else {
- multipartBoundary = generateMultipartBoundary();
- contentType = computeContentType(MULTIPART_FORM_CONTENT_TYPE, multipartBoundary);
- }
-
- long contentLength = getLengthOfParts(parts, multipartBoundary);
-
- return new MultipartBody(parts, contentType, contentLength, multipartBoundary);
- }
-
- private static byte[] generateMultipartBoundary() {
- Random rand = new Random();
- byte[] bytes = new byte[rand.nextInt(11) + 30]; // a random size from 30 to 40
- for (int i = 0; i < bytes.length; i++) {
- bytes[i] = MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)];
- }
- return bytes;
- }
-
- private static String computeContentType(String base, byte[] multipartBoundary) {
- StringBuilder buffer = new StringBuilder(base);
- if (!base.endsWith(";"))
- buffer.append(";");
- return buffer.append(" boundary=").append(new String(multipartBoundary, StandardCharsets.US_ASCII)).toString();
- }
-
- public static long writeBytesToChannel(WritableByteChannel target, byte[] bytes) throws IOException {
-
- int written = 0;
- int maxSpin = 0;
- synchronized (bytes) {
- ByteBuffer message = ByteBuffer.wrap(bytes);
-
- if (target instanceof SocketChannel) {
- final Selector selector = Selector.open();
- try {
- final SocketChannel channel = (SocketChannel) target;
- channel.register(selector, SelectionKey.OP_WRITE);
-
- while (written < bytes.length) {
- selector.select(1000);
- maxSpin++;
- final Set selectedKeys = selector.selectedKeys();
-
- for (SelectionKey key : selectedKeys) {
- if (key.isWritable()) {
- written += target.write(message);
- maxSpin = 0;
- }
- }
- if (maxSpin >= 10) {
- throw new IOException("Unable to write on channel " + target);
- }
- }
- } finally {
- selector.close();
- }
- } else {
- while ((target.isOpen()) && (written < bytes.length)) {
- long nWrite = target.write(message);
- written += nWrite;
- if (nWrite == 0 && maxSpin++ < 10) {
- LOGGER.info("Waiting for writing...");
- try {
- bytes.wait(1000);
- } catch (InterruptedException e) {
- LOGGER.trace(e.getMessage(), e);
- }
- } else {
- if (maxSpin >= 10) {
- throw new IOException("Unable to write on channel " + target);
- }
- maxSpin = 0;
- }
- }
- }
- }
- return written;
- }
-
- public static byte[] getMessageEnd(byte[] partBoundary) throws IOException {
-
- if (partBoundary == null || partBoundary.length == 0) {
- throw new IllegalArgumentException("partBoundary may not be empty");
- }
-
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out);
- visitor.withBytes(EXTRA_BYTES);
- visitor.withBytes(partBoundary);
- visitor.withBytes(EXTRA_BYTES);
- visitor.withBytes(CRLF_BYTES);
-
- return out.toByteArray();
- }
-
- public static long getLengthOfParts(List parts, byte[] partBoundary) {
-
- try {
- if (parts == null) {
- throw new IllegalArgumentException("Parts may not be null");
- }
- long total = 0;
- for (Part part : parts) {
- long l = part.length(partBoundary);
- if (l < 0) {
- return -1;
- }
- total += l;
- }
- total += EXTRA_BYTES.length;
- total += partBoundary.length;
- total += EXTRA_BYTES.length;
- total += CRLF_BYTES.length;
- return total;
- } catch (Exception e) {
- LOGGER.error("An exception occurred while getting the length of the parts", e);
- return 0L;
- }
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java
deleted file mode 100644
index 7f57532459..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/OutputStreamPartVisitor.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-public class OutputStreamPartVisitor implements PartVisitor {
-
- private final OutputStream out;
-
- public OutputStreamPartVisitor(OutputStream out) {
- this.out = out;
- }
-
- @Override
- public void withBytes(byte[] bytes) throws IOException {
- out.write(bytes);
- }
-
- public OutputStream getOutputStream() {
- return out;
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/Part.java b/api/src/main/java/org/asynchttpclient/multipart/Part.java
deleted file mode 100644
index 849d721c1f..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/Part.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import org.asynchttpclient.util.StandardCharsets;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.channels.WritableByteChannel;
-
-public abstract class Part {
-
- /**
- * Carriage return/linefeed as a byte array
- */
- public static final byte[] CRLF_BYTES = "\r\n".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * Content dispostion as a byte array
- */
- public static final byte[] QUOTE_BYTES = "\"".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * Extra characters as a byte array
- */
- public static final byte[] EXTRA_BYTES = "--".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * Content dispostion as a byte array
- */
- public static final byte[] CONTENT_DISPOSITION_BYTES = "Content-Disposition: form-data; name=".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * Content type header as a byte array
- */
- public static final byte[] CONTENT_TYPE_BYTES = "Content-Type: ".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * Content charset as a byte array
- */
- public static final byte[] CHARSET_BYTES = "; charset=".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * Content type header as a byte array
- */
- public static final byte[] CONTENT_TRANSFER_ENCODING_BYTES = "Content-Transfer-Encoding: ".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * Content type header as a byte array
- */
- public static final byte[] CONTENT_ID_BYTES = "Content-ID: ".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * Return the name of this part.
- *
- * @return The name.
- */
- public abstract String getName();
-
- /**
- * Returns the content type of this part.
- *
- * @return the content type, or null
to exclude the content type header
- */
- public abstract String getContentType();
-
- /**
- * Return the character encoding of this part.
- *
- * @return the character encoding, or null
to exclude the character encoding header
- */
- public abstract String getCharSet();
-
- /**
- * Return the transfer encoding of this part.
- *
- * @return the transfer encoding, or null
to exclude the transfer encoding header
- */
- public abstract String getTransferEncoding();
-
- /**
- * Return the content ID of this part.
- *
- * @return the content ID, or null
to exclude the content ID header
- */
- public abstract String getContentId();
-
- /**
- * Tests if this part can be sent more than once.
- *
- * @return true
if {@link #sendData(java.io.OutputStream)} can be successfully called more than once.
- * @since 3.0
- */
- public boolean isRepeatable() {
- return true;
- }
-
- protected void visitStart(PartVisitor visitor, byte[] boundary) throws IOException {
- visitor.withBytes(EXTRA_BYTES);
- visitor.withBytes(boundary);
- }
-
- protected void visitDispositionHeader(PartVisitor visitor) throws IOException {
- if (getName() != null) {
- visitor.withBytes(CRLF_BYTES);
- visitor.withBytes(CONTENT_DISPOSITION_BYTES);
- visitor.withBytes(QUOTE_BYTES);
- visitor.withBytes(getName().getBytes(StandardCharsets.US_ASCII));
- visitor.withBytes(QUOTE_BYTES);
- }
- }
-
- protected void visitContentTypeHeader(PartVisitor visitor) throws IOException {
- String contentType = getContentType();
- if (contentType != null) {
- visitor.withBytes(CRLF_BYTES);
- visitor.withBytes(CONTENT_TYPE_BYTES);
- visitor.withBytes(contentType.getBytes(StandardCharsets.US_ASCII));
- String charSet = getCharSet();
- if (charSet != null) {
- visitor.withBytes(CHARSET_BYTES);
- visitor.withBytes(charSet.getBytes(StandardCharsets.US_ASCII));
- }
- }
- }
-
- protected void visitTransferEncodingHeader(PartVisitor visitor) throws IOException {
- String transferEncoding = getTransferEncoding();
- if (transferEncoding != null) {
- visitor.withBytes(CRLF_BYTES);
- visitor.withBytes(CONTENT_TRANSFER_ENCODING_BYTES);
- visitor.withBytes(transferEncoding.getBytes(StandardCharsets.US_ASCII));
- }
- }
-
- protected void visitContentIdHeader(PartVisitor visitor) throws IOException {
- String contentId = getContentId();
- if (contentId != null) {
- visitor.withBytes(CRLF_BYTES);
- visitor.withBytes(CONTENT_ID_BYTES);
- visitor.withBytes(contentId.getBytes(StandardCharsets.US_ASCII));
- }
- }
-
- protected void visitEndOfHeader(PartVisitor visitor) throws IOException {
- visitor.withBytes(CRLF_BYTES);
- visitor.withBytes(CRLF_BYTES);
- }
-
- protected void visitEnd(PartVisitor visitor) throws IOException {
- visitor.withBytes(CRLF_BYTES);
- }
-
- protected abstract long getDataLength();
-
- protected abstract void sendData(OutputStream out) throws IOException;
-
- /**
- * Write all the data to the output stream. If you override this method make sure to override #length() as well
- *
- * @param out
- * The output stream
- * @param boundary
- * the boundary
- * @throws IOException
- * If an IO problem occurs.
- */
- public void write(OutputStream out, byte[] boundary) throws IOException {
-
- OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out);
-
- visitStart(visitor, boundary);
- visitDispositionHeader(visitor);
- visitContentTypeHeader(visitor);
- visitTransferEncodingHeader(visitor);
- visitContentIdHeader(visitor);
- visitEndOfHeader(visitor);
- sendData(visitor.getOutputStream());
- visitEnd(visitor);
- }
-
- /**
- * Return the full length of all the data. If you override this method make sure to override #send(OutputStream) as well
- *
- * @return long The length.
- */
- public long length(byte[] boundary) {
-
- long dataLength = getDataLength();
- try {
-
- if (dataLength < 0L) {
- return -1L;
- } else {
- CounterPartVisitor visitor = new CounterPartVisitor();
- visitStart(visitor, boundary);
- visitDispositionHeader(visitor);
- visitContentTypeHeader(visitor);
- visitTransferEncodingHeader(visitor);
- visitContentIdHeader(visitor);
- visitEndOfHeader(visitor);
- visitEnd(visitor);
- return dataLength + visitor.getCount();
- }
- } catch (IOException e) {
- // can't happen
- throw new RuntimeException("IOException while computing length, WTF", e);
- }
- }
-
- /**
- * Return a string representation of this object.
- *
- * @return A string representation of this object.
- * @see java.lang.Object#toString()
- */
- public String toString() {
- return this.getName();
- }
-
- public abstract long write(WritableByteChannel target, byte[] boundary) throws IOException;
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java b/api/src/main/java/org/asynchttpclient/multipart/PartBase.java
deleted file mode 100644
index 2f446d18c5..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/PartBase.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-public abstract class PartBase extends Part {
-
- /**
- * Name of the file part.
- */
- private final String name;
-
- /**
- * Content type of the file part.
- */
- private final String contentType;
-
- /**
- * Content encoding of the file part.
- */
- private final String charSet;
-
- /**
- * The transfer encoding.
- */
- private final String transferEncoding;
-
- private final String contentId;
-
- /**
- * Constructor.
- *
- * @param name The name of the part
- * @param contentType The content type, or null
- * @param charSet The character encoding, or null
- * @param transferEncoding The transfer encoding, or null
- * @param contentId The content id, or null
- */
- public PartBase(String name, String contentType, String charSet, String transferEncoding, String contentId) {
-
- if (name == null) {
- throw new NullPointerException("name");
- }
- this.name = name;
- this.contentType = contentType;
- this.charSet = charSet;
- this.transferEncoding = transferEncoding;
- this.contentId = contentId;
- }
-
- /**
- * Returns the name.
- *
- * @return The name.
- */
- public String getName() {
- return this.name;
- }
-
- /**
- * Returns the content type of this part.
- *
- * @return String The name.
- */
- public String getContentType() {
- return this.contentType;
- }
-
- /**
- * Return the character encoding of this part.
- *
- * @return String The name.
- */
- public String getCharSet() {
- return this.charSet;
- }
-
- /**
- * Returns the transfer encoding of this part.
- *
- * @return String The name.
- */
- public String getTransferEncoding() {
- return transferEncoding;
- }
-
- public String getContentId() {
- return contentId;
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java b/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java
deleted file mode 100644
index 150cdfa734..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/PartVisitor.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import java.io.IOException;
-
-public interface PartVisitor {
-
- public void withBytes(byte[] bytes) throws IOException;
-}
diff --git a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java b/api/src/main/java/org/asynchttpclient/multipart/StringPart.java
deleted file mode 100644
index 1dad2f0be3..0000000000
--- a/api/src/main/java/org/asynchttpclient/multipart/StringPart.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-package org.asynchttpclient.multipart;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.channels.WritableByteChannel;
-import java.nio.charset.Charset;
-
-public class StringPart extends PartBase {
-
- /**
- * Default content encoding of string parameters.
- */
- public static final String DEFAULT_CONTENT_TYPE = "text/plain";
-
- /**
- * Default charset of string parameters
- */
- public static final String DEFAULT_CHARSET = "US-ASCII";
-
- /**
- * Default transfer encoding of string parameters
- */
- public static final String DEFAULT_TRANSFER_ENCODING = "8bit";
-
- /**
- * Contents of this StringPart.
- */
- private final byte[] content;
-
- public StringPart(String name, String value, String charset) {
- this(name, value, charset, null);
- }
-
- /**
- * Constructor.
- *
- * @param name
- * The name of the part
- * @param value
- * the string to post
- * @param charset
- * the charset to be used to encode the string, if null
the {@link #DEFAULT_CHARSET default} is used
- * @param contentId
- * the content id
- */
- public StringPart(String name, String value, String charset, String contentId) {
-
- super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, DEFAULT_TRANSFER_ENCODING, contentId);
- if (value == null) {
- throw new IllegalArgumentException("Value may not be null");
- }
- if (value.indexOf(0) != -1) {
- // See RFC 2048, 2.8. "8bit Data"
- throw new IllegalArgumentException("NULs may not be present in string parts");
- }
- content = value.getBytes(Charset.forName(charset));
- }
-
- /**
- * Writes the data to the given OutputStream.
- *
- * @param out
- * the OutputStream to write to
- * @throws java.io.IOException
- * if there is a write error
- */
- protected void sendData(OutputStream out) throws IOException {
- out.write(content);
- }
-
- /**
- * Return the length of the data.
- *
- * @return The length of the data.
- */
- protected long getDataLength() {
- return content.length;
- }
-
- public byte[] getBytes(byte[] boundary) throws IOException {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- write(outputStream, boundary);
- return outputStream.toByteArray();
- }
-
- @Override
- public long write(WritableByteChannel target, byte[] boundary) throws IOException {
- return MultipartUtils.writeBytesToChannel(target, getBytes(boundary));
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java b/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java
deleted file mode 100644
index 687759f755..0000000000
--- a/api/src/main/java/org/asynchttpclient/ntlm/NTLMEngine.java
+++ /dev/null
@@ -1,1284 +0,0 @@
-/*
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * .
- *
- */
-
-package org.asynchttpclient.ntlm;
-
-import org.asynchttpclient.util.Base64;
-import org.asynchttpclient.util.StandardCharsets;
-
-import javax.crypto.Cipher;
-import javax.crypto.spec.SecretKeySpec;
-
-import java.io.UnsupportedEncodingException;
-import java.security.Key;
-import java.security.MessageDigest;
-import java.util.Arrays;
-import java.util.Locale;
-
-/**
- * Provides an implementation for NTLMv1, NTLMv2, and NTLM2 Session forms of the NTLM
- * authentication protocol.
- *
- * @since 4.1
- */
-public class NTLMEngine {
-
- // Flags we use
- protected final static int FLAG_UNICODE_ENCODING = 0x00000001;
- protected final static int FLAG_TARGET_DESIRED = 0x00000004;
- protected final static int FLAG_NEGOTIATE_SIGN = 0x00000010;
- protected final static int FLAG_NEGOTIATE_SEAL = 0x00000020;
- protected final static int FLAG_NEGOTIATE_NTLM = 0x00000200;
- protected final static int FLAG_NEGOTIATE_ALWAYS_SIGN = 0x00008000;
- protected final static int FLAG_NEGOTIATE_NTLM2 = 0x00080000;
- protected final static int FLAG_NEGOTIATE_128 = 0x20000000;
- protected final static int FLAG_NEGOTIATE_KEY_EXCH = 0x40000000;
-
- /**
- * Secure random generator
- */
- private static final java.security.SecureRandom RND_GEN;
-
- static {
- java.security.SecureRandom rnd = null;
- try {
- rnd = java.security.SecureRandom.getInstance("SHA1PRNG");
- } catch (Exception ignored) {
- }
- RND_GEN = rnd;
- }
-
- /**
- * Character encoding
- */
- static final String DEFAULT_CHARSET = "ASCII";
-
- /**
- * The character set to use for encoding the credentials
- */
- private String credentialCharset = DEFAULT_CHARSET;
-
- private static final byte[] NTLMSSP_BYTES = "NTLMSSP".getBytes(StandardCharsets.US_ASCII);
- private static final byte[] MAGIC_CONSTANT = "KGS!@#$%".getBytes(StandardCharsets.US_ASCII);
-
- /**
- * The signature string as bytes in the default encoding
- */
- private static byte[] SIGNATURE;
-
- static {
- byte[] bytesWithoutNull = new byte[0];
- bytesWithoutNull = NTLMSSP_BYTES;
- SIGNATURE = new byte[bytesWithoutNull.length + 1];
- System.arraycopy(bytesWithoutNull, 0, SIGNATURE, 0, bytesWithoutNull.length);
- SIGNATURE[bytesWithoutNull.length] = (byte) 0x00;
- }
-
- public static final NTLMEngine INSTANCE = new NTLMEngine();
-
- /**
- * Returns the response for the given message.
- *
- * @param message the message that was received from the server.
- * @param username the username to authenticate with.
- * @param password the password to authenticate with.
- * @param host The host.
- * @param domain the NT domain to authenticate in.
- * @return The response.
- * @throws NTLMEngineException If the messages cannot be retrieved.
- */
- final String getResponseFor(String message, String username, String password, String host, String domain) throws NTLMEngineException {
-
- final String response;
- if (message == null || message.trim().length() == 0) {
- response = getType1Message(host, domain);
- } else {
- Type2Message t2m = new Type2Message(message);
- response = getType3Message(username, password, host, domain, t2m.getChallenge(), t2m.getFlags(), t2m.getTarget(),
- t2m.getTargetInfo());
- }
- return response;
- }
-
- /**
- * Creates the first message (type 1 message) in the NTLM authentication
- * sequence. This message includes the user name, domain and host for the
- * authentication session.
- *
- * @param host the computer name of the host requesting authentication.
- * @param domain The domain to authenticate with.
- * @return String the message to add to the HTTP request header.
- */
- String getType1Message(String host, String domain) throws NTLMEngineException {
- try {
- return new Type1Message(domain, host).getResponse();
- } catch (UnsupportedEncodingException e) {
- throw new NTLMEngineException("Unsupported encoding", e);
- }
- }
-
- /**
- * Creates the type 3 message using the given server nonce. The type 3
- * message includes all the information for authentication, host, domain,
- * username and the result of encrypting the nonce sent by the server using
- * the user's password as the key.
- *
- * @param user The user name. This should not include the domain name.
- * @param password The password.
- * @param host The host that is originating the authentication request.
- * @param domain The domain to authenticate within.
- * @param nonce the 8 byte array the server sent.
- * @return The type 3 message.
- * @throws NTLMEngineException If {@encrypt(byte[],byte[])} fails.
- */
- String getType3Message(String user, String password, String host, String domain, byte[] nonce, int type2Flags, String target,
- byte[] targetInformation) throws NTLMEngineException {
- try {
- return new Type3Message(domain, host, user, password, nonce, type2Flags, target, targetInformation).getResponse();
- } catch (UnsupportedEncodingException e) {
- throw new NTLMEngineException("Unsupported encoding", e);
- }
- }
-
- /**
- * @return Returns the credentialCharset.
- */
- String getCredentialCharset() {
- return credentialCharset;
- }
-
- /**
- * @param credentialCharset The credentialCharset to set.
- */
- void setCredentialCharset(String credentialCharset) {
- this.credentialCharset = credentialCharset;
- }
-
- /**
- * Strip dot suffix from a name
- */
- private static String stripDotSuffix(String value) {
- int index = value.indexOf(".");
- if (index != -1)
- return value.substring(0, index);
- return value;
- }
-
- /**
- * Convert host to standard form
- */
- private static String convertHost(String host) {
- return stripDotSuffix(host);
- }
-
- /**
- * Convert domain to standard form
- */
- private static String convertDomain(String domain) {
- return stripDotSuffix(domain);
- }
-
- private static int readULong(byte[] src, int index) throws NTLMEngineException {
- if (src.length < index + 4)
- throw new NTLMEngineException("NTLM authentication - buffer too small for DWORD");
- return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8) | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24);
- }
-
- private static int readUShort(byte[] src, int index) throws NTLMEngineException {
- if (src.length < index + 2)
- throw new NTLMEngineException("NTLM authentication - buffer too small for WORD");
- return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8);
- }
-
- private static byte[] readSecurityBuffer(byte[] src, int index) throws NTLMEngineException {
- int length = readUShort(src, index);
- int offset = readULong(src, index + 4);
- if (src.length < offset + length)
- throw new NTLMEngineException("NTLM authentication - buffer too small for data item");
- byte[] buffer = new byte[length];
- System.arraycopy(src, offset, buffer, 0, length);
- return buffer;
- }
-
- /**
- * Calculate a challenge block
- */
- private static byte[] makeRandomChallenge() throws NTLMEngineException {
- if (RND_GEN == null) {
- throw new NTLMEngineException("Random generator not available");
- }
- byte[] rval = new byte[8];
- synchronized (RND_GEN) {
- RND_GEN.nextBytes(rval);
- }
- return rval;
- }
-
- /**
- * Calculate an NTLM2 challenge block
- */
- private static byte[] makeNTLM2RandomChallenge() throws NTLMEngineException {
- if (RND_GEN == null) {
- throw new NTLMEngineException("Random generator not available");
- }
- byte[] rval = new byte[24];
- synchronized (RND_GEN) {
- RND_GEN.nextBytes(rval);
- }
- // 8-byte challenge, padded with zeros to 24 bytes.
- Arrays.fill(rval, 8, 24, (byte) 0x00);
- return rval;
- }
-
- /**
- * Calculates the LM Response for the given challenge, using the specified
- * password.
- *
- * @param password The user's password.
- * @param challenge The Type 2 challenge from the server.
- * @return The LM Response.
- */
- static byte[] getLMResponse(String password, byte[] challenge) throws NTLMEngineException {
- byte[] lmHash = lmHash(password);
- return lmResponse(lmHash, challenge);
- }
-
- /**
- * Calculates the NTLM Response for the given challenge, using the specified
- * password.
- *
- * @param password The user's password.
- * @param challenge The Type 2 challenge from the server.
- * @return The NTLM Response.
- */
- static byte[] getNTLMResponse(String password, byte[] challenge) throws NTLMEngineException {
- byte[] ntlmHash = ntlmHash(password);
- return lmResponse(ntlmHash, challenge);
- }
-
- /**
- * Calculates the NTLMv2 Response for the given challenge, using the
- * specified authentication target, username, password, target information
- * block, and client challenge.
- *
- * @param target The authentication target (i.e., domain).
- * @param user The username.
- * @param password The user's password.
- * @param targetInformation The target information block from the Type 2 message.
- * @param challenge The Type 2 challenge from the server.
- * @param clientChallenge The random 8-byte client challenge.
- * @return The NTLMv2 Response.
- */
- static byte[] getNTLMv2Response(String target, String user, String password, byte[] challenge, byte[] clientChallenge,
- byte[] targetInformation) throws NTLMEngineException {
- byte[] ntlmv2Hash = ntlmv2Hash(target, user, password);
- byte[] blob = createBlob(clientChallenge, targetInformation);
- return lmv2Response(ntlmv2Hash, challenge, blob);
- }
-
- /**
- * Calculates the LMv2 Response for the given challenge, using the specified
- * authentication target, username, password, and client challenge.
- *
- * @param target The authentication target (i.e., domain).
- * @param user The username.
- * @param password The user's password.
- * @param challenge The Type 2 challenge from the server.
- * @param clientChallenge The random 8-byte client challenge.
- * @return The LMv2 Response.
- */
- static byte[] getLMv2Response(String target, String user, String password, byte[] challenge, byte[] clientChallenge)
- throws NTLMEngineException {
- byte[] ntlmv2Hash = ntlmv2Hash(target, user, password);
- return lmv2Response(ntlmv2Hash, challenge, clientChallenge);
- }
-
- /**
- * Calculates the NTLM2 Session Response for the given challenge, using the
- * specified password and client challenge.
- *
- * @param password The user's password.
- * @param challenge The Type 2 challenge from the server.
- * @param clientChallenge The random 8-byte client challenge.
- * @return The NTLM2 Session Response. This is placed in the NTLM response
- * field of the Type 3 message; the LM response field contains the
- * client challenge, null-padded to 24 bytes.
- */
- static byte[] getNTLM2SessionResponse(String password, byte[] challenge, byte[] clientChallenge) throws NTLMEngineException {
- try {
- byte[] ntlmHash = ntlmHash(password);
-
- // Look up MD5 algorithm (was necessary on jdk 1.4.2)
- // This used to be needed, but java 1.5.0_07 includes the MD5
- // algorithm (finally)
- // Class x = Class.forName("gnu.crypto.hash.MD5");
- // Method updateMethod = x.getMethod("update",new
- // Class[]{byte[].class});
- // Method digestMethod = x.getMethod("digest",new Class[0]);
- // Object mdInstance = x.newInstance();
- // updateMethod.invoke(mdInstance,new Object[]{challenge});
- // updateMethod.invoke(mdInstance,new Object[]{clientChallenge});
- // byte[] digest = (byte[])digestMethod.invoke(mdInstance,new
- // Object[0]);
-
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- md5.update(challenge);
- md5.update(clientChallenge);
- byte[] digest = md5.digest();
-
- byte[] sessionHash = new byte[8];
- System.arraycopy(digest, 0, sessionHash, 0, 8);
- return lmResponse(ntlmHash, sessionHash);
- } catch (Exception e) {
- if (e instanceof NTLMEngineException)
- throw (NTLMEngineException) e;
- throw new NTLMEngineException(e.getMessage(), e);
- }
- }
-
- /**
- * Creates the LM Hash of the user's password.
- *
- * @param password The password.
- * @return The LM Hash of the given password, used in the calculation of the
- * LM Response.
- */
- private static byte[] lmHash(String password) throws NTLMEngineException {
- try {
- byte[] oemPassword = password.toUpperCase(Locale.ENGLISH).getBytes(StandardCharsets.US_ASCII);
- int length = Math.min(oemPassword.length, 14);
- byte[] keyBytes = new byte[14];
- System.arraycopy(oemPassword, 0, keyBytes, 0, length);
- Key lowKey = createDESKey(keyBytes, 0);
- Key highKey = createDESKey(keyBytes, 7);
- Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
- des.init(Cipher.ENCRYPT_MODE, lowKey);
- byte[] lowHash = des.doFinal(MAGIC_CONSTANT);
- des.init(Cipher.ENCRYPT_MODE, highKey);
- byte[] highHash = des.doFinal(MAGIC_CONSTANT);
- byte[] lmHash = new byte[16];
- System.arraycopy(lowHash, 0, lmHash, 0, 8);
- System.arraycopy(highHash, 0, lmHash, 8, 8);
- return lmHash;
- } catch (Exception e) {
- throw new NTLMEngineException(e.getMessage(), e);
- }
- }
-
- /**
- * Creates the NTLM Hash of the user's password.
- *
- * @param password The password.
- * @return The NTLM Hash of the given password, used in the calculation of
- * the NTLM Response and the NTLMv2 and LMv2 Hashes.
- */
- private static byte[] ntlmHash(String password) throws NTLMEngineException {
- byte[] unicodePassword = password.getBytes(StandardCharsets.UNICODE_LITTLE_UNMARKED);
- MD4 md4 = new MD4();
- md4.update(unicodePassword);
- return md4.getOutput();
- }
-
- /**
- * Creates the NTLMv2 Hash of the user's password.
- *
- * @param target The authentication target (i.e., domain).
- * @param user The username.
- * @param password The password.
- * @return The NTLMv2 Hash, used in the calculation of the NTLMv2 and LMv2
- * Responses.
- */
- private static byte[] ntlmv2Hash(String target, String user, String password) throws NTLMEngineException {
- byte[] ntlmHash = ntlmHash(password);
- HMACMD5 hmacMD5 = new HMACMD5(ntlmHash);
- // Upper case username, mixed case target!!
- hmacMD5.update(user.toUpperCase(Locale.ENGLISH).getBytes(StandardCharsets.UNICODE_LITTLE_UNMARKED));
- hmacMD5.update(target.getBytes(StandardCharsets.UNICODE_LITTLE_UNMARKED));
- return hmacMD5.getOutput();
- }
-
- /**
- * Creates the LM Response from the given hash and Type 2 challenge.
- *
- * @param hash The LM or NTLM Hash.
- * @param challenge The server challenge from the Type 2 message.
- * @return The response (either LM or NTLM, depending on the provided hash).
- */
- private static byte[] lmResponse(byte[] hash, byte[] challenge) throws NTLMEngineException {
- try {
- byte[] keyBytes = new byte[21];
- System.arraycopy(hash, 0, keyBytes, 0, 16);
- Key lowKey = createDESKey(keyBytes, 0);
- Key middleKey = createDESKey(keyBytes, 7);
- Key highKey = createDESKey(keyBytes, 14);
- Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
- des.init(Cipher.ENCRYPT_MODE, lowKey);
- byte[] lowResponse = des.doFinal(challenge);
- des.init(Cipher.ENCRYPT_MODE, middleKey);
- byte[] middleResponse = des.doFinal(challenge);
- des.init(Cipher.ENCRYPT_MODE, highKey);
- byte[] highResponse = des.doFinal(challenge);
- byte[] lmResponse = new byte[24];
- System.arraycopy(lowResponse, 0, lmResponse, 0, 8);
- System.arraycopy(middleResponse, 0, lmResponse, 8, 8);
- System.arraycopy(highResponse, 0, lmResponse, 16, 8);
- return lmResponse;
- } catch (Exception e) {
- throw new NTLMEngineException(e.getMessage(), e);
- }
- }
-
- /**
- * Creates the LMv2 Response from the given hash, client data, and Type 2
- * challenge.
- *
- * @param hash The NTLMv2 Hash.
- * @param clientData The client data (blob or client challenge).
- * @param challenge The server challenge from the Type 2 message.
- * @return The response (either NTLMv2 or LMv2, depending on the client
- * data).
- */
- private static byte[] lmv2Response(byte[] hash, byte[] challenge, byte[] clientData) throws NTLMEngineException {
- HMACMD5 hmacMD5 = new HMACMD5(hash);
- hmacMD5.update(challenge);
- hmacMD5.update(clientData);
- byte[] mac = hmacMD5.getOutput();
- byte[] lmv2Response = new byte[mac.length + clientData.length];
- System.arraycopy(mac, 0, lmv2Response, 0, mac.length);
- System.arraycopy(clientData, 0, lmv2Response, mac.length, clientData.length);
- return lmv2Response;
- }
-
- /**
- * Creates the NTLMv2 blob from the given target information block and
- * client challenge.
- *
- * @param targetInformation The target information block from the Type 2 message.
- * @param clientChallenge The random 8-byte client challenge.
- * @return The blob, used in the calculation of the NTLMv2 Response.
- */
- private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformation) {
- byte[] blobSignature = new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00 };
- byte[] reserved = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
- byte[] unknown1 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
- long time = System.currentTimeMillis();
- time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch.
- time *= 10000; // tenths of a microsecond.
- // convert to little-endian byte array.
- byte[] timestamp = new byte[8];
- for (int i = 0; i < 8; i++) {
- timestamp[i] = (byte) time;
- time >>>= 8;
- }
- byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 + unknown1.length + targetInformation.length];
- int offset = 0;
- System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length);
- offset += blobSignature.length;
- System.arraycopy(reserved, 0, blob, offset, reserved.length);
- offset += reserved.length;
- System.arraycopy(timestamp, 0, blob, offset, timestamp.length);
- offset += timestamp.length;
- System.arraycopy(clientChallenge, 0, blob, offset, 8);
- offset += 8;
- System.arraycopy(unknown1, 0, blob, offset, unknown1.length);
- offset += unknown1.length;
- System.arraycopy(targetInformation, 0, blob, offset, targetInformation.length);
- return blob;
- }
-
- /**
- * Creates a DES encryption key from the given key material.
- *
- * @param bytes A byte array containing the DES key material.
- * @param offset The offset in the given byte array at which the 7-byte key
- * material starts.
- * @return A DES encryption key created from the key material starting at
- * the specified offset in the given byte array.
- */
- private static Key createDESKey(byte[] bytes, int offset) {
- byte[] keyBytes = new byte[7];
- System.arraycopy(bytes, offset, keyBytes, 0, 7);
- byte[] material = new byte[8];
- material[0] = keyBytes[0];
- material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1);
- material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2);
- material[3] = (byte) (keyBytes[2] << 5 | (keyBytes[3] & 0xff) >>> 3);
- material[4] = (byte) (keyBytes[3] << 4 | (keyBytes[4] & 0xff) >>> 4);
- material[5] = (byte) (keyBytes[4] << 3 | (keyBytes[5] & 0xff) >>> 5);
- material[6] = (byte) (keyBytes[5] << 2 | (keyBytes[6] & 0xff) >>> 6);
- material[7] = (byte) (keyBytes[6] << 1);
- oddParity(material);
- return new SecretKeySpec(material, "DES");
- }
-
- /**
- * Applies odd parity to the given byte array.
- *
- * @param bytes The data whose parity bits are to be adjusted for odd parity.
- */
- private static void oddParity(byte[] bytes) {
- for (int i = 0; i < bytes.length; i++) {
- byte b = bytes[i];
- boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0;
- if (needsParity) {
- bytes[i] |= (byte) 0x01;
- } else {
- bytes[i] &= (byte) 0xfe;
- }
- }
- }
-
- /**
- * NTLM message generation, base class
- */
- static class NTLMMessage {
- /**
- * The current response
- */
- private byte[] messageContents = null;
-
- /**
- * The current output position
- */
- private int currentOutputPosition = 0;
-
- /**
- * Constructor to use when message contents are not yet known
- */
- NTLMMessage() {
- }
-
- /**
- * Constructor to use when message contents are known
- */
- NTLMMessage(String messageBody, int expectedType) throws NTLMEngineException {
- messageContents = Base64.decode(messageBody);
-
- // Look for NTLM message
- if (messageContents.length < SIGNATURE.length)
- throw new NTLMEngineException("NTLM message decoding error - packet too short");
- int i = 0;
- while (i < SIGNATURE.length) {
- if (messageContents[i] != SIGNATURE[i])
- throw new NTLMEngineException("NTLM message expected - instead got unrecognized bytes");
- i++;
- }
-
- // Check to be sure there's a type 2 message indicator next
- int type = readULong(SIGNATURE.length);
- if (type != expectedType)
- throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType) + " message expected - instead got type "
- + Integer.toString(type));
-
- currentOutputPosition = messageContents.length;
- }
-
- /**
- * Get the length of the signature and flags, so calculations can adjust
- * offsets accordingly.
- */
- protected int getPreambleLength() {
- return SIGNATURE.length + 4;
- }
-
- /**
- * Get the message length
- */
- protected int getMessageLength() {
- return currentOutputPosition;
- }
-
- /**
- * Read a byte from a position within the message buffer
- */
- protected byte readByte(int position) throws NTLMEngineException {
- if (messageContents.length < position + 1)
- throw new NTLMEngineException("NTLM: Message too short");
- return messageContents[position];
- }
-
- /**
- * Read a bunch of bytes from a position in the message buffer
- */
- protected void readBytes(byte[] buffer, int position) throws NTLMEngineException {
- if (messageContents.length < position + buffer.length)
- throw new NTLMEngineException("NTLM: Message too short");
- System.arraycopy(messageContents, position, buffer, 0, buffer.length);
- }
-
- /**
- * Read a ushort from a position within the message buffer
- */
- protected int readUShort(int position) throws NTLMEngineException {
- return NTLMEngine.readUShort(messageContents, position);
- }
-
- /**
- * Read a ulong from a position within the message buffer
- */
- protected int readULong(int position) throws NTLMEngineException {
- return NTLMEngine.readULong(messageContents, position);
- }
-
- /**
- * Read a security buffer from a position within the message buffer
- */
- protected byte[] readSecurityBuffer(int position) throws NTLMEngineException {
- return NTLMEngine.readSecurityBuffer(messageContents, position);
- }
-
- /**
- * Prepares the object to create a response of the given length.
- *
- * @param maxlength the maximum length of the response to prepare, not
- * including the type and the signature (which this method
- * adds).
- */
- protected void prepareResponse(int maxlength, int messageType) {
- messageContents = new byte[maxlength];
- currentOutputPosition = 0;
- addBytes(SIGNATURE);
- addULong(messageType);
- }
-
- /**
- * Adds the given byte to the response.
- *
- * @param b the byte to add.
- */
- protected void addByte(byte b) {
- messageContents[currentOutputPosition] = b;
- currentOutputPosition++;
- }
-
- /**
- * Adds the given bytes to the response.
- *
- * @param bytes the bytes to add.
- */
- protected void addBytes(byte[] bytes) {
- for (int i = 0; i < bytes.length; i++) {
- messageContents[currentOutputPosition] = bytes[i];
- currentOutputPosition++;
- }
- }
-
- /**
- * Adds a USHORT to the response
- */
- protected void addUShort(int value) {
- addByte((byte) (value & 0xff));
- addByte((byte) (value >> 8 & 0xff));
- }
-
- /**
- * Adds a ULong to the response
- */
- protected void addULong(int value) {
- addByte((byte) (value & 0xff));
- addByte((byte) (value >> 8 & 0xff));
- addByte((byte) (value >> 16 & 0xff));
- addByte((byte) (value >> 24 & 0xff));
- }
-
- /**
- * Returns the response that has been generated after shrinking the
- * array if required and base64 encodes the response.
- *
- * @return The response as above.
- */
- String getResponse() throws UnsupportedEncodingException {
- byte[] resp;
- if (messageContents.length > currentOutputPosition) {
- byte[] tmp = new byte[currentOutputPosition];
- for (int i = 0; i < currentOutputPosition; i++) {
- tmp[i] = messageContents[i];
- }
- resp = tmp;
- } else {
- resp = messageContents;
- }
- return Base64.encode(resp);
- }
-
- }
-
- /**
- * Type 1 message assembly class
- */
- static class Type1Message extends NTLMMessage {
- protected byte[] hostBytes;
- protected byte[] domainBytes;
-
- /**
- * Constructor. Include the arguments the message will need
- */
- Type1Message(String domain, String host) throws NTLMEngineException {
- super();
- // Strip off domain name from the host!
- host = convertHost(host);
- // Use only the base domain name!
- domain = convertDomain(domain);
-
- hostBytes = host.getBytes(StandardCharsets.UNICODE_LITTLE_UNMARKED);
- domainBytes = domain.toUpperCase(Locale.ENGLISH).getBytes(StandardCharsets.UNICODE_LITTLE_UNMARKED);
- }
-
- /**
- * Getting the response involves building the message before returning
- * it
- */
- @Override
- String getResponse() throws UnsupportedEncodingException {
- // Now, build the message. Calculate its length first, including
- // signature or type.
- int finalLength = 32 + hostBytes.length + domainBytes.length;
-
- // Set up the response. This will initialize the signature, message
- // type, and flags.
- prepareResponse(finalLength, 1);
-
- // Flags. These are the complete set of flags we support.
- addULong(FLAG_NEGOTIATE_NTLM | FLAG_NEGOTIATE_NTLM2 | FLAG_NEGOTIATE_SIGN | FLAG_NEGOTIATE_SEAL |
- /*
- * FLAG_NEGOTIATE_ALWAYS_SIGN | FLAG_NEGOTIATE_KEY_EXCH |
- */
- FLAG_UNICODE_ENCODING | FLAG_TARGET_DESIRED | FLAG_NEGOTIATE_128);
-
- // Domain length (two times).
- addUShort(domainBytes.length);
- addUShort(domainBytes.length);
-
- // Domain offset.
- addULong(hostBytes.length + 32);
-
- // Host length (two times).
- addUShort(hostBytes.length);
- addUShort(hostBytes.length);
-
- // Host offset (always 32).
- addULong(32);
-
- // Host String.
- addBytes(hostBytes);
-
- // Domain String.
- addBytes(domainBytes);
-
- return super.getResponse();
- }
-
- }
-
- /**
- * Type 2 message class
- */
- static class Type2Message extends NTLMMessage {
- protected byte[] challenge;
- protected String target;
- protected byte[] targetInfo;
- protected int flags;
-
- Type2Message(String message) throws NTLMEngineException {
- super(message, 2);
-
- // Parse out the rest of the info we need from the message
- // The nonce is the 8 bytes starting from the byte in position 24.
- challenge = new byte[8];
- readBytes(challenge, 24);
-
- flags = readULong(20);
- if ((flags & FLAG_UNICODE_ENCODING) == 0)
- throw new NTLMEngineException("NTLM type 2 message has flags that make no sense: " + Integer.toString(flags));
- // Do the target!
- target = null;
- // The TARGET_DESIRED flag is said to not have understood semantics
- // in Type2 messages, so use the length of the packet to decide
- // how to proceed instead
- if (getMessageLength() >= 12 + 8) {
- byte[] bytes = readSecurityBuffer(12);
- if (bytes.length != 0) {
- target = new String(bytes, StandardCharsets.UNICODE_LITTLE_UNMARKED);
- }
- }
-
- // Do the target info!
- targetInfo = null;
- // TARGET_DESIRED flag cannot be relied on, so use packet length
- if (getMessageLength() >= 40 + 8) {
- byte[] bytes = readSecurityBuffer(40);
- if (bytes.length != 0) {
- targetInfo = bytes;
- }
- }
- }
-
- /**
- * Retrieve the challenge
- */
- byte[] getChallenge() {
- return challenge;
- }
-
- /**
- * Retrieve the target
- */
- String getTarget() {
- return target;
- }
-
- /**
- * Retrieve the target info
- */
- byte[] getTargetInfo() {
- return targetInfo;
- }
-
- /**
- * Retrieve the response flags
- */
- int getFlags() {
- return flags;
- }
-
- }
-
- /**
- * Type 3 message assembly class
- */
- static class Type3Message extends NTLMMessage {
- // Response flags from the type2 message
- protected int type2Flags;
-
- protected byte[] domainBytes;
- protected byte[] hostBytes;
- protected byte[] userBytes;
-
- protected byte[] lmResp;
- protected byte[] ntResp;
-
- /**
- * Constructor. Pass the arguments we will need
- */
- Type3Message(String domain, String host, String user, String password, byte[] nonce, int type2Flags, String target,
- byte[] targetInformation) throws NTLMEngineException {
- // Save the flags
- this.type2Flags = type2Flags;
-
- // Strip off domain name from the host!
- host = convertHost(host);
- // Use only the base domain name!
- domain = convertDomain(domain);
-
- // Use the new code to calculate the responses, including v2 if that
- // seems warranted.
- try {
- if (targetInformation != null && target != null) {
- byte[] clientChallenge = makeRandomChallenge();
- ntResp = getNTLMv2Response(target, user, password, nonce, clientChallenge, targetInformation);
- lmResp = getLMv2Response(target, user, password, nonce, clientChallenge);
- } else {
- if ((type2Flags & FLAG_NEGOTIATE_NTLM2) != 0) {
- // NTLM2 session stuff is requested
- byte[] clientChallenge = makeNTLM2RandomChallenge();
-
- ntResp = getNTLM2SessionResponse(password, nonce, clientChallenge);
- lmResp = clientChallenge;
-
- // All the other flags we send (signing, sealing, key
- // exchange) are supported, but they don't do anything
- // at all in an
- // NTLM2 context! So we're done at this point.
- } else {
- ntResp = getNTLMResponse(password, nonce);
- lmResp = getLMResponse(password, nonce);
- }
- }
- } catch (NTLMEngineException e) {
- // This likely means we couldn't find the MD4 hash algorithm -
- // fail back to just using LM
- ntResp = new byte[0];
- lmResp = getLMResponse(password, nonce);
- }
-
- domainBytes = domain.toUpperCase(Locale.ENGLISH).getBytes(StandardCharsets.UNICODE_LITTLE_UNMARKED);
- hostBytes = host.getBytes(StandardCharsets.UNICODE_LITTLE_UNMARKED);
- userBytes = user.getBytes(StandardCharsets.UNICODE_LITTLE_UNMARKED);
- }
-
- /**
- * Assemble the response
- */
- @Override
- String getResponse() throws UnsupportedEncodingException {
- int ntRespLen = ntResp.length;
- int lmRespLen = lmResp.length;
-
- int domainLen = domainBytes.length;
- int hostLen = hostBytes.length;
- int userLen = userBytes.length;
-
- // Calculate the layout within the packet
- int lmRespOffset = 64;
- int ntRespOffset = lmRespOffset + lmRespLen;
- int domainOffset = ntRespOffset + ntRespLen;
- int userOffset = domainOffset + domainLen;
- int hostOffset = userOffset + userLen;
- int finalLength = hostOffset + hostLen;
-
- // Start the response. Length includes signature and type
- prepareResponse(finalLength, 3);
-
- // LM Resp Length (twice)
- addUShort(lmRespLen);
- addUShort(lmRespLen);
-
- // LM Resp Offset
- addULong(lmRespOffset);
-
- // NT Resp Length (twice)
- addUShort(ntRespLen);
- addUShort(ntRespLen);
-
- // NT Resp Offset
- addULong(ntRespOffset);
-
- // Domain length (twice)
- addUShort(domainLen);
- addUShort(domainLen);
-
- // Domain offset.
- addULong(domainOffset);
-
- // User Length (twice)
- addUShort(userLen);
- addUShort(userLen);
-
- // User offset
- addULong(userOffset);
-
- // Host length (twice)
- addUShort(hostLen);
- addUShort(hostLen);
-
- // Host offset
- addULong(hostOffset);
-
- // 4 bytes of zeros - not sure what this is
- addULong(0);
-
- // Message length
- addULong(finalLength);
-
- // Flags. Currently: NEGOTIATE_NTLM + UNICODE_ENCODING +
- // TARGET_DESIRED + NEGOTIATE_128
- addULong(FLAG_NEGOTIATE_NTLM | FLAG_UNICODE_ENCODING | FLAG_TARGET_DESIRED | FLAG_NEGOTIATE_128
- | (type2Flags & FLAG_NEGOTIATE_NTLM2) | (type2Flags & FLAG_NEGOTIATE_SIGN) | (type2Flags & FLAG_NEGOTIATE_SEAL)
- | (type2Flags & FLAG_NEGOTIATE_KEY_EXCH) | (type2Flags & FLAG_NEGOTIATE_ALWAYS_SIGN));
-
- // Add the actual data
- addBytes(lmResp);
- addBytes(ntResp);
- addBytes(domainBytes);
- addBytes(userBytes);
- addBytes(hostBytes);
-
- return super.getResponse();
- }
- }
-
- static void writeULong(byte[] buffer, int value, int offset) {
- buffer[offset] = (byte) (value & 0xff);
- buffer[offset + 1] = (byte) (value >> 8 & 0xff);
- buffer[offset + 2] = (byte) (value >> 16 & 0xff);
- buffer[offset + 3] = (byte) (value >> 24 & 0xff);
- }
-
- static int F(int x, int y, int z) {
- return ((x & y) | (~x & z));
- }
-
- static int G(int x, int y, int z) {
- return ((x & y) | (x & z) | (y & z));
- }
-
- static int H(int x, int y, int z) {
- return (x ^ y ^ z);
- }
-
- static int rotintlft(int val, int numbits) {
- return ((val << numbits) | (val >>> (32 - numbits)));
- }
-
- /**
- * Cryptography support - MD4. The following class was based loosely on the
- * RFC and on code found at http://www.cs.umd.edu/~harry/jotp/src/md.java.
- * Code correctness was verified by looking at MD4.java from the jcifs
- * library (http://jcifs.samba.org). It was massaged extensively to the
- * final form found here by Karl Wright (kwright@metacarta.com).
- */
- static class MD4 {
- protected int A = 0x67452301;
- protected int B = 0xefcdab89;
- protected int C = 0x98badcfe;
- protected int D = 0x10325476;
- protected long count = 0L;
- protected byte[] dataBuffer = new byte[64];
-
- MD4() {
- }
-
- void update(byte[] input) {
- // We always deal with 512 bits at a time. Correspondingly, there is
- // a buffer 64 bytes long that we write data into until it gets
- // full.
- int curBufferPos = (int) (count & 63L);
- int inputIndex = 0;
- while (input.length - inputIndex + curBufferPos >= dataBuffer.length) {
- // We have enough data to do the next step. Do a partial copy
- // and a transform, updating inputIndex and curBufferPos
- // accordingly
- int transferAmt = dataBuffer.length - curBufferPos;
- System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
- count += transferAmt;
- curBufferPos = 0;
- inputIndex += transferAmt;
- processBuffer();
- }
-
- // If there's anything left, copy it into the buffer and leave it.
- // We know there's not enough left to process.
- if (inputIndex < input.length) {
- int transferAmt = input.length - inputIndex;
- System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt);
- count += transferAmt;
- }
- }
-
- byte[] getOutput() {
- // Feed pad/length data into engine. This must round out the input
- // to a multiple of 512 bits.
- int bufferIndex = (int) (count & 63L);
- int padLen = (bufferIndex < 56) ? (56 - bufferIndex) : (120 - bufferIndex);
- byte[] postBytes = new byte[padLen + 8];
- // Leading 0x80, specified amount of zero padding, then length in
- // bits.
- postBytes[0] = (byte) 0x80;
- // Fill out the last 8 bytes with the length
- for (int i = 0; i < 8; i++) {
- postBytes[padLen + i] = (byte) ((count * 8) >>> (8 * i));
- }
-
- // Update the engine
- update(postBytes);
-
- // Calculate final result
- byte[] result = new byte[16];
- writeULong(result, A, 0);
- writeULong(result, B, 4);
- writeULong(result, C, 8);
- writeULong(result, D, 12);
- return result;
- }
-
- protected void processBuffer() {
- // Convert current buffer to 16 ulongs
- int[] d = new int[16];
-
- for (int i = 0; i < 16; i++) {
- d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8) + ((dataBuffer[i * 4 + 2] & 0xff) << 16)
- + ((dataBuffer[i * 4 + 3] & 0xff) << 24);
- }
-
- // Do a round of processing
- int AA = A;
- int BB = B;
- int CC = C;
- int DD = D;
- round1(d);
- round2(d);
- round3(d);
- A += AA;
- B += BB;
- C += CC;
- D += DD;
-
- }
-
- protected void round1(int[] d) {
- A = rotintlft((A + F(B, C, D) + d[0]), 3);
- D = rotintlft((D + F(A, B, C) + d[1]), 7);
- C = rotintlft((C + F(D, A, B) + d[2]), 11);
- B = rotintlft((B + F(C, D, A) + d[3]), 19);
-
- A = rotintlft((A + F(B, C, D) + d[4]), 3);
- D = rotintlft((D + F(A, B, C) + d[5]), 7);
- C = rotintlft((C + F(D, A, B) + d[6]), 11);
- B = rotintlft((B + F(C, D, A) + d[7]), 19);
-
- A = rotintlft((A + F(B, C, D) + d[8]), 3);
- D = rotintlft((D + F(A, B, C) + d[9]), 7);
- C = rotintlft((C + F(D, A, B) + d[10]), 11);
- B = rotintlft((B + F(C, D, A) + d[11]), 19);
-
- A = rotintlft((A + F(B, C, D) + d[12]), 3);
- D = rotintlft((D + F(A, B, C) + d[13]), 7);
- C = rotintlft((C + F(D, A, B) + d[14]), 11);
- B = rotintlft((B + F(C, D, A) + d[15]), 19);
- }
-
- protected void round2(int[] d) {
- A = rotintlft((A + G(B, C, D) + d[0] + 0x5a827999), 3);
- D = rotintlft((D + G(A, B, C) + d[4] + 0x5a827999), 5);
- C = rotintlft((C + G(D, A, B) + d[8] + 0x5a827999), 9);
- B = rotintlft((B + G(C, D, A) + d[12] + 0x5a827999), 13);
-
- A = rotintlft((A + G(B, C, D) + d[1] + 0x5a827999), 3);
- D = rotintlft((D + G(A, B, C) + d[5] + 0x5a827999), 5);
- C = rotintlft((C + G(D, A, B) + d[9] + 0x5a827999), 9);
- B = rotintlft((B + G(C, D, A) + d[13] + 0x5a827999), 13);
-
- A = rotintlft((A + G(B, C, D) + d[2] + 0x5a827999), 3);
- D = rotintlft((D + G(A, B, C) + d[6] + 0x5a827999), 5);
- C = rotintlft((C + G(D, A, B) + d[10] + 0x5a827999), 9);
- B = rotintlft((B + G(C, D, A) + d[14] + 0x5a827999), 13);
-
- A = rotintlft((A + G(B, C, D) + d[3] + 0x5a827999), 3);
- D = rotintlft((D + G(A, B, C) + d[7] + 0x5a827999), 5);
- C = rotintlft((C + G(D, A, B) + d[11] + 0x5a827999), 9);
- B = rotintlft((B + G(C, D, A) + d[15] + 0x5a827999), 13);
-
- }
-
- protected void round3(int[] d) {
- A = rotintlft((A + H(B, C, D) + d[0] + 0x6ed9eba1), 3);
- D = rotintlft((D + H(A, B, C) + d[8] + 0x6ed9eba1), 9);
- C = rotintlft((C + H(D, A, B) + d[4] + 0x6ed9eba1), 11);
- B = rotintlft((B + H(C, D, A) + d[12] + 0x6ed9eba1), 15);
-
- A = rotintlft((A + H(B, C, D) + d[2] + 0x6ed9eba1), 3);
- D = rotintlft((D + H(A, B, C) + d[10] + 0x6ed9eba1), 9);
- C = rotintlft((C + H(D, A, B) + d[6] + 0x6ed9eba1), 11);
- B = rotintlft((B + H(C, D, A) + d[14] + 0x6ed9eba1), 15);
-
- A = rotintlft((A + H(B, C, D) + d[1] + 0x6ed9eba1), 3);
- D = rotintlft((D + H(A, B, C) + d[9] + 0x6ed9eba1), 9);
- C = rotintlft((C + H(D, A, B) + d[5] + 0x6ed9eba1), 11);
- B = rotintlft((B + H(C, D, A) + d[13] + 0x6ed9eba1), 15);
-
- A = rotintlft((A + H(B, C, D) + d[3] + 0x6ed9eba1), 3);
- D = rotintlft((D + H(A, B, C) + d[11] + 0x6ed9eba1), 9);
- C = rotintlft((C + H(D, A, B) + d[7] + 0x6ed9eba1), 11);
- B = rotintlft((B + H(C, D, A) + d[15] + 0x6ed9eba1), 15);
-
- }
-
- }
-
- /**
- * Cryptography support - HMACMD5 - algorithmically based on various web
- * resources by Karl Wright
- */
- static class HMACMD5 {
- protected byte[] ipad;
- protected byte[] opad;
- protected MessageDigest md5;
-
- HMACMD5(byte[] key) throws NTLMEngineException {
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (Exception ex) {
- // Umm, the algorithm doesn't exist - throw an
- // NTLMEngineException!
- throw new NTLMEngineException("Error getting md5 message digest implementation: " + ex.getMessage(), ex);
- }
-
- // Initialize the pad buffers with the key
- ipad = new byte[64];
- opad = new byte[64];
-
- int keyLength = key.length;
- if (keyLength > 64) {
- // Use MD5 of the key instead, as described in RFC 2104
- md5.update(key);
- key = md5.digest();
- keyLength = key.length;
- }
- int i = 0;
- while (i < keyLength) {
- ipad[i] = (byte) (key[i] ^ (byte) 0x36);
- opad[i] = (byte) (key[i] ^ (byte) 0x5c);
- i++;
- }
- while (i < 64) {
- ipad[i] = (byte) 0x36;
- opad[i] = (byte) 0x5c;
- i++;
- }
-
- // Very important: update the digest with the ipad buffer
- md5.reset();
- md5.update(ipad);
-
- }
-
- /**
- * Grab the current digest. This is the "answer".
- */
- byte[] getOutput() {
- byte[] digest = md5.digest();
- md5.update(opad);
- return md5.digest(digest);
- }
-
- /**
- * Update by adding a complete array
- */
- void update(byte[] input) {
- md5.update(input);
- }
-
- /**
- * Update the algorithm
- */
- void update(byte[] input, int offset, int length) {
- md5.update(input, offset, length);
- }
-
- }
-
- public String generateType1Msg(final String domain, final String workstation) throws NTLMEngineException {
- return getType1Message(workstation, domain);
- }
-
- public String generateType3Msg(final String username, final String password, final String domain, final String workstation,
- final String challenge) throws NTLMEngineException {
- Type2Message t2m = new Type2Message(challenge);
- return getType3Message(username, password, workstation, domain, t2m.getChallenge(), t2m.getFlags(), t2m.getTarget(),
- t2m.getTargetInfo());
- }
-
-}
diff --git a/api/src/main/java/org/asynchttpclient/oauth/ConsumerKey.java b/api/src/main/java/org/asynchttpclient/oauth/ConsumerKey.java
deleted file mode 100644
index 1962798330..0000000000
--- a/api/src/main/java/org/asynchttpclient/oauth/ConsumerKey.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.asynchttpclient.oauth;
-
-/**
- * Value class for OAuth consumer keys.
- */
-public class ConsumerKey {
- private final String key;
- private final String secret;
-
- public ConsumerKey(String key, String secret) {
- this.key = key;
- this.secret = secret;
- }
-
- public String getKey() {
- return key;
- }
-
- public String getSecret() {
- return secret;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("{Consumer key, key=");
- appendValue(sb, key);
- sb.append(", secret=");
- appendValue(sb, secret);
- sb.append("}");
- return sb.toString();
- }
-
- private void appendValue(StringBuilder sb, String value) {
- if (value == null) {
- sb.append("null");
- } else {
- sb.append('"');
- sb.append(value);
- sb.append('"');
- }
- }
-
- @Override
- public int hashCode() {
- return key.hashCode() + secret.hashCode();
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this)
- return true;
- if (o == null || o.getClass() != getClass())
- return false;
- ConsumerKey other = (ConsumerKey) o;
- return key.equals(other.key) && secret.equals(other.secret);
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java b/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java
deleted file mode 100644
index b13f5a9c58..0000000000
--- a/api/src/main/java/org/asynchttpclient/oauth/OAuthSignatureCalculator.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.asynchttpclient.oauth;
-
-import org.asynchttpclient.FluentStringsMap;
-import org.asynchttpclient.Request;
-import org.asynchttpclient.RequestBuilderBase;
-import org.asynchttpclient.SignatureCalculator;
-import org.asynchttpclient.util.Base64;
-import org.asynchttpclient.util.StandardCharsets;
-import org.asynchttpclient.util.UTF8UrlEncoder;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-
-/**
- * Simple OAuth signature calculator that can used for constructing client signatures
- * for accessing services that use OAuth for authorization.
- *
- * Supports most common signature inclusion and calculation methods: HMAC-SHA1 for
- * calculation, and Header inclusion as inclusion method. Nonce generation uses
- * simple random numbers with base64 encoding.
- *
- * @author tatu (tatu.saloranta@iki.fi)
- */
-public class OAuthSignatureCalculator implements SignatureCalculator {
- public final static String HEADER_AUTHORIZATION = "Authorization";
-
- private static final String KEY_OAUTH_CONSUMER_KEY = "oauth_consumer_key";
- private static final String KEY_OAUTH_NONCE = "oauth_nonce";
- private static final String KEY_OAUTH_SIGNATURE = "oauth_signature";
- private static final String KEY_OAUTH_SIGNATURE_METHOD = "oauth_signature_method";
- private static final String KEY_OAUTH_TIMESTAMP = "oauth_timestamp";
- private static final String KEY_OAUTH_TOKEN = "oauth_token";
- private static final String KEY_OAUTH_VERSION = "oauth_version";
-
- private static final String OAUTH_VERSION_1_0 = "1.0";
- private static final String OAUTH_SIGNATURE_METHOD = "HMAC-SHA1";
-
- /**
- * To generate Nonce, need some (pseudo)randomness; no need for
- * secure variant here.
- */
- protected final Random random;
-
- protected final byte[] nonceBuffer = new byte[16];
-
- protected final ThreadSafeHMAC mac;
-
- protected final ConsumerKey consumerAuth;
-
- protected final RequestToken userAuth;
-
- /**
- * @param consumerAuth Consumer key to use for signature calculation
- * @param userAuth Request/access token to use for signature calculation
- */
- public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) {
- mac = new ThreadSafeHMAC(consumerAuth, userAuth);
- this.consumerAuth = consumerAuth;
- this.userAuth = userAuth;
- random = new Random(System.identityHashCode(this) + System.currentTimeMillis());
- }
-
- //@Override // silly 1.5; doesn't allow this for interfaces
-
- public void calculateAndAddSignature(String baseURL, Request request, RequestBuilderBase> requestBuilder) {
- String method = request.getMethod(); // POST etc
- String nonce = generateNonce();
- long timestamp = System.currentTimeMillis() / 1000L;
- String signature = calculateSignature(method, baseURL, timestamp, nonce, request.getParams(), request.getQueryParams());
- String headerValue = constructAuthHeader(signature, nonce, timestamp);
- requestBuilder.setHeader(HEADER_AUTHORIZATION, headerValue);
- }
-
- /**
- * Method for calculating OAuth signature using HMAC/SHA-1 method.
- */
- public String calculateSignature(String method, String baseURL, long oauthTimestamp, String nonce, FluentStringsMap formParams,
- FluentStringsMap queryParams) {
- StringBuilder signedText = new StringBuilder(100);
- signedText.append(method); // POST / GET etc (nothing to URL encode)
- signedText.append('&');
-
- /* 07-Oct-2010, tatu: URL may contain default port number; if so, need to extract
- * from base URL.
- */
- if (baseURL.startsWith("http:")) {
- int i = baseURL.indexOf(":80/", 4);
- if (i > 0) {
- baseURL = baseURL.substring(0, i) + baseURL.substring(i + 3);
- }
- } else if (baseURL.startsWith("https:")) {
- int i = baseURL.indexOf(":443/", 5);
- if (i > 0) {
- baseURL = baseURL.substring(0, i) + baseURL.substring(i + 4);
- }
- }
- signedText.append(UTF8UrlEncoder.encode(baseURL));
-
- /**
- * List of all query and form parameters added to this request; needed
- * for calculating request signature
- */
- OAuthParameterSet allParameters = new OAuthParameterSet();
-
- // start with standard OAuth parameters we need
- allParameters.add(KEY_OAUTH_CONSUMER_KEY, consumerAuth.getKey());
- allParameters.add(KEY_OAUTH_NONCE, nonce);
- allParameters.add(KEY_OAUTH_SIGNATURE_METHOD, OAUTH_SIGNATURE_METHOD);
- allParameters.add(KEY_OAUTH_TIMESTAMP, String.valueOf(oauthTimestamp));
- allParameters.add(KEY_OAUTH_TOKEN, userAuth.getKey());
- allParameters.add(KEY_OAUTH_VERSION, OAUTH_VERSION_1_0);
-
- if (formParams != null) {
- for (Map.Entry> entry : formParams) {
- String key = entry.getKey();
- for (String value : entry.getValue()) {
- allParameters.add(key, value);
- }
- }
- }
- if (queryParams != null) {
- for (Map.Entry> entry : queryParams) {
- String key = entry.getKey();
- for (String value : entry.getValue()) {
- allParameters.add(key, value);
- }
- }
- }
- String encodedParams = allParameters.sortAndConcat();
-
- // and all that needs to be URL encoded (... again!)
- signedText.append('&');
- UTF8UrlEncoder.appendEncoded(signedText, encodedParams);
-
- byte[] rawBase = signedText.toString().getBytes(StandardCharsets.UTF_8);
- byte[] rawSignature = mac.digest(rawBase);
- // and finally, base64 encoded... phew!
- return Base64.encode(rawSignature);
- }
-
- /**
- * Method used for constructing
- */
- public String constructAuthHeader(String signature, String nonce, long oauthTimestamp) {
- StringBuilder sb = new StringBuilder(200);
- sb.append("OAuth ");
- sb.append(KEY_OAUTH_CONSUMER_KEY).append("=\"").append(consumerAuth.getKey()).append("\", ");
- sb.append(KEY_OAUTH_TOKEN).append("=\"").append(userAuth.getKey()).append("\", ");
- sb.append(KEY_OAUTH_SIGNATURE_METHOD).append("=\"").append(OAUTH_SIGNATURE_METHOD).append("\", ");
-
- // careful: base64 has chars that need URL encoding:
- sb.append(KEY_OAUTH_SIGNATURE).append("=\"");
- UTF8UrlEncoder.appendEncoded(sb, signature).append("\", ");
- sb.append(KEY_OAUTH_TIMESTAMP).append("=\"").append(oauthTimestamp).append("\", ");
-
- // also: nonce may contain things that need URL encoding (esp. when using base64):
- sb.append(KEY_OAUTH_NONCE).append("=\"");
- UTF8UrlEncoder.appendEncoded(sb, nonce);
- sb.append("\", ");
-
- sb.append(KEY_OAUTH_VERSION).append("=\"").append(OAUTH_VERSION_1_0).append("\"");
- return sb.toString();
- }
-
- private synchronized String generateNonce() {
- random.nextBytes(nonceBuffer);
- // let's use base64 encoding over hex, slightly more compact than hex or decimals
- return Base64.encode(nonceBuffer);
- // return String.valueOf(Math.abs(random.nextLong()));
- }
-
- /**
- * Container for parameters used for calculating OAuth signature.
- * About the only confusing aspect is that of whether entries are to be sorted
- * before encoded or vice versa: if my reading is correct, encoding is to occur
- * first, then sorting; although this should rarely matter (since sorting is primary
- * by key, which usually has nothing to encode)... of course, rarely means that
- * when it would occur it'd be harder to track down.
- */
- final static class OAuthParameterSet {
- final private ArrayList allParameters = new ArrayList();
-
- public OAuthParameterSet() {
- }
-
- public OAuthParameterSet add(String key, String value) {
- Parameter p = new Parameter(UTF8UrlEncoder.encode(key), UTF8UrlEncoder.encode(value));
- allParameters.add(p);
- return this;
- }
-
- public String sortAndConcat() {
- // then sort them (AFTER encoding, important)
- Parameter[] params = allParameters.toArray(new Parameter[allParameters.size()]);
- Arrays.sort(params);
-
- // and build parameter section using pre-encoded pieces:
- StringBuilder encodedParams = new StringBuilder(100);
- for (Parameter param : params) {
- if (encodedParams.length() > 0) {
- encodedParams.append('&');
- }
- encodedParams.append(param.key()).append('=').append(param.value());
- }
- return encodedParams.toString();
- }
- }
-
- /**
- * Helper class for sorting query and form parameters that we need
- */
- final static class Parameter implements Comparable {
- private final String key, value;
-
- public Parameter(String key, String value) {
- this.key = key;
- this.value = value;
- }
-
- public String key() {
- return key;
- }
-
- public String value() {
- return value;
- }
-
- //@Override // silly 1.5; doesn't allow this for interfaces
-
- public int compareTo(Parameter other) {
- int diff = key.compareTo(other.key);
- if (diff == 0) {
- diff = value.compareTo(other.value);
- }
- return diff;
- }
-
- @Override
- public String toString() {
- return key + "=" + value;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
-
- Parameter parameter = (Parameter) o;
-
- if (!key.equals(parameter.key))
- return false;
- if (!value.equals(parameter.value))
- return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = key.hashCode();
- result = 31 * result + value.hashCode();
- return result;
- }
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/oauth/RequestToken.java b/api/src/main/java/org/asynchttpclient/oauth/RequestToken.java
deleted file mode 100644
index 2fd02c4244..0000000000
--- a/api/src/main/java/org/asynchttpclient/oauth/RequestToken.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.asynchttpclient.oauth;
-
-/**
- * Value class used for OAuth tokens (request secret, access secret);
- * simple container with two parts, public id part ("key") and
- * confidential ("secret") part.
- */
-public class RequestToken {
- private final String key;
- private final String secret;
-
- public RequestToken(String key, String token) {
- this.key = key;
- this.secret = token;
- }
-
- public String getKey() {
- return key;
- }
-
- public String getSecret() {
- return secret;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("{ key=");
- appendValue(sb, key);
- sb.append(", secret=");
- appendValue(sb, secret);
- sb.append("}");
- return sb.toString();
- }
-
- private void appendValue(StringBuilder sb, String value) {
- if (value == null) {
- sb.append("null");
- } else {
- sb.append('"');
- sb.append(value);
- sb.append('"');
- }
- }
-
- @Override
- public int hashCode() {
- return key.hashCode() + secret.hashCode();
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this)
- return true;
- if (o == null || o.getClass() != getClass())
- return false;
- RequestToken other = (RequestToken) o;
- return key.equals(other.key) && secret.equals(other.secret);
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java b/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java
deleted file mode 100644
index 028020f758..0000000000
--- a/api/src/main/java/org/asynchttpclient/oauth/ThreadSafeHMAC.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2010 Ning, Inc.
- *
- * Ning licenses this file to you under the Apache License, version 2.0
- * (the "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.asynchttpclient.oauth;
-
-import org.asynchttpclient.util.StandardCharsets;
-import org.asynchttpclient.util.UTF8UrlEncoder;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * Since cloning (of MAC instances) is not necessarily supported on all platforms
- * (and specifically seems to fail on MacOS), let's wrap synchronization/reuse details here.
- * Assumption is that this is bit more efficient (even considering synchronization)
- * than locating and reconstructing instance each time.
- * In future we may want to use soft references and thread local instance.
- *
- * @author tatu (tatu.saloranta@iki.fi)
- */
-public class ThreadSafeHMAC {
- private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
-
- private final Mac mac;
-
- public ThreadSafeHMAC(ConsumerKey consumerAuth, RequestToken userAuth) {
- byte[] keyBytes = (UTF8UrlEncoder.encode(consumerAuth.getSecret()) + "&" + UTF8UrlEncoder.encode(userAuth.getSecret()))
- .getBytes(StandardCharsets.UTF_8);
- SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM);
-
- // Get an hmac_sha1 instance and initialize with the signing key
- try {
- mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
- mac.init(signingKey);
- } catch (Exception e) {
- throw new IllegalArgumentException(e);
- }
-
- }
-
- public synchronized byte[] digest(byte[] message) {
- mac.reset();
- return mac.doFinal(message);
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java b/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java
deleted file mode 100644
index d2b4fc225f..0000000000
--- a/api/src/main/java/org/asynchttpclient/providers/ResponseBase.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package org.asynchttpclient.providers;
-
-import static org.asynchttpclient.util.MiscUtil.isNonEmpty;
-
-import org.asynchttpclient.FluentCaseInsensitiveStringsMap;
-import org.asynchttpclient.HttpResponseBodyPart;
-import org.asynchttpclient.HttpResponseHeaders;
-import org.asynchttpclient.HttpResponseStatus;
-import org.asynchttpclient.Response;
-import org.asynchttpclient.cookie.Cookie;
-import org.asynchttpclient.util.AsyncHttpProviderUtils;
-
-import java.net.URI;
-import java.util.Collections;
-import java.util.List;
-
-public abstract class ResponseBase implements Response {
- protected final static String DEFAULT_CHARSET = "ISO-8859-1";
-
- protected final List bodyParts;
- protected final HttpResponseHeaders headers;
- protected final HttpResponseStatus status;
- private List cookies;
-
- protected ResponseBase(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) {
- this.bodyParts = bodyParts;
- this.headers = headers;
- this.status = status;
- }
-
- protected abstract List buildCookies();
-
- protected String calculateCharset(String charset) {
-
- if (charset == null) {
- String contentType = getContentType();
- if (contentType != null)
- charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null
- }
- return charset != null ? charset : DEFAULT_CHARSET;
- }
-
- @Override
- public final int getStatusCode() {
- return status.getStatusCode();
- }
-
- @Override
- public final String getStatusText() {
- return status.getStatusText();
- }
-
- @Override
- public final URI getUri() {
- return status.getUri();
- }
-
- @Override
- public final String getContentType() {
- return headers != null ? getHeader("Content-Type") : null;
- }
-
- @Override
- public final String getHeader(String name) {
- return headers != null ? getHeaders().getFirstValue(name) : null;
- }
-
- @Override
- public final List getHeaders(String name) {
- return headers != null ? getHeaders().get(name) : null;
- }
-
- @Override
- public final FluentCaseInsensitiveStringsMap getHeaders() {
- return headers != null ? headers.getHeaders() : new FluentCaseInsensitiveStringsMap();
- }
-
- @Override
- public final boolean isRedirected() {
- switch (status.getStatusCode()) {
- case 301:
- case 302:
- case 303:
- case 307:
- case 308:
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public List getCookies() {
-
- if (headers == null) {
- return Collections.emptyList();
- }
-
- if (cookies == null) {
- cookies = buildCookies();
- }
- return cookies;
-
- }
-
- @Override
- public boolean hasResponseStatus() {
- return status != null;
- }
-
- @Override
- public boolean hasResponseHeaders() {
- return headers != null && isNonEmpty(headers.getHeaders());
- }
-
- @Override
- public boolean hasResponseBody() {
- return isNonEmpty(bodyParts);
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/simple/HeaderMap.java b/api/src/main/java/org/asynchttpclient/simple/HeaderMap.java
deleted file mode 100644
index 92476cc6a3..0000000000
--- a/api/src/main/java/org/asynchttpclient/simple/HeaderMap.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package org.asynchttpclient.simple;
-
-/*
- * Copyright (c) 2010 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-
-import org.asynchttpclient.FluentCaseInsensitiveStringsMap;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A map containing headers with the sole purpose of being given to
- * {@link SimpleAHCTransferListener#onHeaders(String, HeaderMap)}.
- *
- * @author Benjamin Hanzelmann
- */
-public class HeaderMap implements Map> {
-
- private FluentCaseInsensitiveStringsMap headers;
-
- public HeaderMap(FluentCaseInsensitiveStringsMap headers) {
- this.headers = headers;
- }
-
- public Set keySet() {
- return headers.keySet();
- }
-
- public Set>> entrySet() {
- return headers.entrySet();
- }
-
- public int size() {
- return headers.size();
- }
-
- public boolean isEmpty() {
- return headers.isEmpty();
- }
-
- public boolean containsKey(Object key) {
- return headers.containsKey(key);
- }
-
- public boolean containsValue(Object value) {
- return headers.containsValue(value);
- }
-
- /**
- * @see FluentCaseInsensitiveStringsMap#getFirstValue(String)
- */
- public String getFirstValue(String key) {
- return headers.getFirstValue(key);
- }
-
- /**
- * @see FluentCaseInsensitiveStringsMap#getJoinedValue(String, String)
- */
- public String getJoinedValue(String key, String delimiter) {
- return headers.getJoinedValue(key, delimiter);
- }
-
- public List get(Object key) {
- return headers.get(key);
- }
-
- /**
- * Only read access is supported.
- */
- public List put(String key, List value) {
- throw new UnsupportedOperationException("Only read access is supported.");
- }
-
- /**
- * Only read access is supported.
- */
- public List remove(Object key) {
- throw new UnsupportedOperationException("Only read access is supported.");
- }
-
- /**
- * Only read access is supported.
- */
- public void putAll(Map extends String, ? extends List> t) {
- throw new UnsupportedOperationException("Only read access is supported.");
-
- }
-
- /**
- * Only read access is supported.
- */
- public void clear() {
- throw new UnsupportedOperationException("Only read access is supported.");
- }
-
- /**
- * Only read access is supported.
- */
- public Collection> values() {
- return headers.values();
- }
-
-}
diff --git a/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java b/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java
deleted file mode 100644
index b8e300f020..0000000000
--- a/api/src/main/java/org/asynchttpclient/simple/SimpleAHCTransferListener.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.asynchttpclient.simple;
-
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-
-import org.asynchttpclient.SimpleAsyncHttpClient;
-
-/**
- * A simple transfer listener for use with the {@link SimpleAsyncHttpClient}.
- *
- * Note: This listener does not cover requests failing before a connection is
- * established. For error handling, see
- * {@link org.asynchttpclient.SimpleAsyncHttpClient.Builder#setDefaultThrowableHandler(org.asynchttpclient.ThrowableHandler)}
- *
- * @author Benjamin Hanzelmann
- */
-public interface SimpleAHCTransferListener {
-
- /**
- * This method is called after the connection status is received.
- *
- * @param url the url for the connection.
- * @param statusCode the received status code.
- * @param statusText the received status text.
- */
- void onStatus(String url, int statusCode, String statusText);
-
- /**
- * This method is called after the response headers are received.
- *
- * @param url the url for the connection.
- * @param headers the received headers, never {@code null}.
- */
- void onHeaders(String url, HeaderMap headers);
-
- /**
- * This method is called when bytes of the responses body are received.
- *
- * @param url the url for the connection.
- * @param amount the number of transferred bytes so far.
- * @param current the number of transferred bytes since the last call to this
- * method.
- * @param total the total number of bytes to be transferred. This is taken
- * from the Content-Length-header and may be unspecified (-1).
- */
- void onBytesReceived(String url, long amount, long current, long total);
-
- /**
- * This method is called when bytes are sent.
- *
- * @param url the url for the connection.
- * @param amount the number of transferred bytes so far.
- * @param current the number of transferred bytes since the last call to this
- * method.
- * @param total the total number of bytes to be transferred. This is taken
- * from the Content-Length-header and may be unspecified (-1).
- */
- void onBytesSent(String url, long amount, long current, long total);
-
- /**
- * This method is called when the request is completed.
- *
- * @param url the url for the connection.
- * @param statusCode the received status code.
- * @param statusText the received status text.
- */
- void onCompleted(String url, int statusCode, String statusText);
-
-}
diff --git a/api/src/main/java/org/asynchttpclient/spnego/SpnegoEngine.java b/api/src/main/java/org/asynchttpclient/spnego/SpnegoEngine.java
deleted file mode 100644
index dc371e0294..0000000000
--- a/api/src/main/java/org/asynchttpclient/spnego/SpnegoEngine.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-/*
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * .
- */
-
-package org.asynchttpclient.spnego;
-
-import org.asynchttpclient.util.Base64;
-import org.ietf.jgss.GSSContext;
-import org.ietf.jgss.GSSException;
-import org.ietf.jgss.GSSManager;
-import org.ietf.jgss.GSSName;
-import org.ietf.jgss.Oid;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-
-/**
- * SPNEGO (Simple and Protected GSSAPI Negotiation Mechanism) authentication scheme.
- *
- * @since 4.1
- */
-public class SpnegoEngine {
-
- private static final String SPNEGO_OID = "1.3.6.1.5.5.2";
- private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
-
- private final Logger log = LoggerFactory.getLogger(getClass());
-
- private final SpnegoTokenGenerator spnegoGenerator;
-
- public SpnegoEngine(final SpnegoTokenGenerator spnegoGenerator) {
- this.spnegoGenerator = spnegoGenerator;
- }
-
- public SpnegoEngine() {
- this(null);
- }
-
- private static SpnegoEngine instance;
-
- public static SpnegoEngine instance() {
- if (instance == null)
- instance = new SpnegoEngine();
- return instance;
- }
-
- public String generateToken(String server) throws Throwable {
- GSSContext gssContext = null;
- byte[] token = null; // base64 decoded challenge
- Oid negotiationOid = null;
-
- try {
- log.debug("init {}", server);
- /*
- * Using the SPNEGO OID is the correct method. Kerberos v5 works for IIS but not JBoss. Unwrapping the initial token when using SPNEGO OID looks like what is described
- * here...
- *
- * http://msdn.microsoft.com/en-us/library/ms995330.aspx
- *
- * Another helpful URL...
- *
- * http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/tsec_SPNEGO_token.html
- *
- * Unfortunately SPNEGO is JRE >=1.6.
- */
-
- /** Try SPNEGO by default, fall back to Kerberos later if error */
- negotiationOid = new Oid(SPNEGO_OID);
-
- boolean tryKerberos = false;
- try {
- GSSManager manager = GSSManager.getInstance();
- GSSName serverName = manager.createName("HTTP@" + server, GSSName.NT_HOSTBASED_SERVICE);
- gssContext = manager.createContext(serverName.canonicalize(negotiationOid), negotiationOid, null,
- GSSContext.DEFAULT_LIFETIME);
- gssContext.requestMutualAuth(true);
- gssContext.requestCredDeleg(true);
- } catch (GSSException ex) {
- log.error("generateToken", ex);
- // BAD MECH means we are likely to be using 1.5, fall back to Kerberos MECH.
- // Rethrow any other exception.
- if (ex.getMajor() == GSSException.BAD_MECH) {
- log.debug("GSSException BAD_MECH, retry with Kerberos MECH");
- tryKerberos = true;
- } else {
- throw ex;
- }
-
- }
- if (tryKerberos) {
- /* Kerberos v5 GSS-API mechanism defined in RFC 1964. */
- log.debug("Using Kerberos MECH {}", KERBEROS_OID);
- negotiationOid = new Oid(KERBEROS_OID);
- GSSManager manager = GSSManager.getInstance();
- GSSName serverName = manager.createName("HTTP@" + server, GSSName.NT_HOSTBASED_SERVICE);
- gssContext = manager.createContext(serverName.canonicalize(negotiationOid), negotiationOid, null,
- GSSContext.DEFAULT_LIFETIME);
- gssContext.requestMutualAuth(true);
- gssContext.requestCredDeleg(true);
- }
-
- // TODO suspicious: this will always be null because no value has been assigned before. Assign directly?
- if (token == null) {
- token = new byte[0];
- }
-
- token = gssContext.initSecContext(token, 0, token.length);
- if (token == null) {
- throw new Exception("GSS security context initialization failed");
- }
-
- /*
- * IIS accepts Kerberos and SPNEGO tokens. Some other servers Jboss, Glassfish? seem to only accept SPNEGO. Below wraps Kerberos into SPNEGO token.
- */
- if (spnegoGenerator != null && negotiationOid.toString().equals(KERBEROS_OID)) {
- token = spnegoGenerator.generateSpnegoDERObject(token);
- }
-
- gssContext.dispose();
-
- String tokenstr = new String(Base64.encode(token));
- log.debug("Sending response '{}' back to the server", tokenstr);
-
- return tokenstr;
- } catch (GSSException gsse) {
- log.error("generateToken", gsse);
- if (gsse.getMajor() == GSSException.DEFECTIVE_CREDENTIAL || gsse.getMajor() == GSSException.CREDENTIALS_EXPIRED)
- throw new Exception(gsse.getMessage(), gsse);
- if (gsse.getMajor() == GSSException.NO_CRED)
- throw new Exception(gsse.getMessage(), gsse);
- if (gsse.getMajor() == GSSException.DEFECTIVE_TOKEN || gsse.getMajor() == GSSException.DUPLICATE_TOKEN
- || gsse.getMajor() == GSSException.OLD_TOKEN)
- throw new Exception(gsse.getMessage(), gsse);
- // other error
- throw new Exception(gsse.getMessage());
- } catch (IOException ex) {
- throw new Exception(ex.getMessage());
- }
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java b/api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java
deleted file mode 100644
index d32424daf9..0000000000
--- a/api/src/main/java/org/asynchttpclient/util/AllowAllHostnameVerifier.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.util;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.SSLSession;
-
-public class AllowAllHostnameVerifier implements HostnameVerifier {
- public boolean verify(String s, SSLSession sslSession) {
- return true;
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java b/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java
deleted file mode 100644
index 386319b2a9..0000000000
--- a/api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.util;
-
-import org.asynchttpclient.AsyncHttpClientConfig;
-import org.asynchttpclient.AsyncHttpProvider;
-import org.asynchttpclient.HttpResponseBodyPart;
-import org.asynchttpclient.Request;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.util.List;
-
-/**
- * {@link org.asynchttpclient.AsyncHttpProvider} common utilities.
- */
-public class AsyncHttpProviderUtils {
-
- public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed");
-
- static {
- REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[] {});
- }
-
- private final static byte[] NO_BYTES = new byte[0];
-
- public final static Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1;
-
- public static final void validateSupportedScheme(URI uri) {
- final String scheme = uri.getScheme();
- if (scheme == null || !scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https") && !scheme.equalsIgnoreCase("ws")
- && !scheme.equalsIgnoreCase("wss")) {
- throw new IllegalArgumentException("The URI scheme, of the URI " + uri
- + ", must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss'");
- }
- }
-
- public final static URI createUri(String u) {
- URI uri = URI.create(u);
- validateSupportedScheme(uri);
-
- String path = uri.getPath();
- if (path == null) {
- throw new IllegalArgumentException("The URI path, of the URI " + uri + ", must be non-null");
- } else if (path.length() > 0 && path.charAt(0) != '/') {
- throw new IllegalArgumentException("The URI path, of the URI " + uri + ". must start with a '/'");
- } else if (path.length() == 0) {
- return URI.create(u + "/");
- }
-
- return uri;
- }
-
- public static String getBaseUrl(String url) {
- return getBaseUrl(createUri(url));
- }
-
- public final static String getBaseUrl(URI uri) {
- String url = uri.getScheme() + "://" + uri.getAuthority();
- int port = uri.getPort();
- if (port == -1) {
- port = getPort(uri);
- url += ":" + port;
- }
- return url;
- }
-
- public final static String getAuthority(URI uri) {
- String url = uri.getAuthority();
- int port = uri.getPort();
- if (port == -1) {
- port = getPort(uri);
- url += ":" + port;
- }
- return url;
- }
-
- /**
- * @param bodyParts NON EMPTY body part
- * @param maxLen
- * @return
- * @throws UnsupportedEncodingException
- */
- public final static byte[] contentToBytes(List bodyParts, int maxLen) throws UnsupportedEncodingException {
- final int partCount = bodyParts.size();
- if (partCount == 0) {
- return NO_BYTES;
- }
- if (partCount == 1) {
- byte[] chunk = bodyParts.get(0).getBodyPartBytes();
- if (chunk.length <= maxLen) {
- return chunk;
- }
- byte[] result = new byte[maxLen];
- System.arraycopy(chunk, 0, result, 0, maxLen);
- return result;
- }
- int size = 0;
- byte[] result = new byte[maxLen];
- for (HttpResponseBodyPart part : bodyParts) {
- byte[] chunk = part.getBodyPartBytes();
- int amount = Math.min(maxLen - size, chunk.length);
- System.arraycopy(chunk, 0, result, size, amount);
- size += amount;
- if (size == maxLen) {
- return result;
- }
- }
- if (size < maxLen) {
- byte[] old = result;
- result = new byte[old.length];
- System.arraycopy(old, 0, result, 0, old.length);
- }
- return result;
- }
-
- public final static String getHost(URI uri) {
- String host = uri.getHost();
- if (host == null) {
- host = uri.getAuthority();
- }
- return host;
- }
-
- public final static URI getRedirectUri(URI uri, String location) {
- if (location == null)
- throw new IllegalArgumentException("URI " + uri + " was redirected to null location");
-
- URI locationURI = null;
- try {
- locationURI = new URI(location);
- } catch (URISyntaxException e) {
- // rich, we have a badly encoded location, let's try to encode the query params
- String[] parts = location.split("\\?");
- if (parts.length != 2) {
- throw new IllegalArgumentException("Don't know how to turn this location into a proper URI:" + location, e);
- } else {
- StringBuilder properUrl = new StringBuilder(location.length()).append(parts[0]).append("?");
-
- String[] queryParams = parts[1].split("&");
- for (int i = 0; i < queryParams.length; i++) {
- String queryParam = queryParams[i];
- if (i != 0)
- properUrl.append("&");
- String[] nameValue = queryParam.split("=", 2);
- UTF8UrlEncoder.appendEncoded(properUrl, nameValue[0]);
- if (nameValue.length == 2) {
- properUrl.append("=");
- UTF8UrlEncoder.appendEncoded(properUrl, nameValue[1]);
- }
- }
-
- locationURI = URI.create(properUrl.toString());
- }
- }
-
- URI redirectUri = uri.resolve(locationURI);
-
- String scheme = redirectUri.getScheme();
-
- if (scheme == null || !scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https") && !scheme.equals("ws")
- && !scheme.equals("wss")) {
- throw new IllegalArgumentException("The URI scheme, of the URI " + redirectUri
- + ", must be equal (ignoring case) to 'ws, 'wss', 'http', or 'https'");
- }
-
- return redirectUri.normalize();
- }
-
- public final static int getPort(URI uri) {
- int port = uri.getPort();
- if (port == -1)
- port = uri.getScheme().equals("http") || uri.getScheme().equals("ws") ? 80 : 443;
- return port;
- }
-
- public static String constructUserAgent(Class extends AsyncHttpProvider> httpProvider, AsyncHttpClientConfig config) {
- return new StringBuilder("AHC (").append(httpProvider.getSimpleName()).append(" - ").append(System.getProperty("os.name"))
- .append(" - ").append(System.getProperty("os.version")).append(" - ").append(System.getProperty("java.version"))
- .append(" - ").append(Runtime.getRuntime().availableProcessors()).append(" core(s))").toString();
- }
-
- public static String parseCharset(String contentType) {
- for (String part : contentType.split(";")) {
- if (part.trim().startsWith("charset=")) {
- String[] val = part.split("=");
- if (val.length > 1) {
- String charset = val[1].trim();
- // Quite a lot of sites have charset="CHARSET",
- // e.g. charset="utf-8". Note the quotes. This is
- // not correct, but client should be able to handle
- // it (all browsers do, Apache HTTP Client and Grizzly
- // strip it by default)
- // This is a poor man's trim("\"").trim("'")
- return charset.replaceAll("\"", "").replaceAll("'", "");
- }
- }
- }
- return null;
- }
-
- public static int secondsFromNow(long timeMillis) {
- long maxAgeMillis = timeMillis - System.currentTimeMillis();
- return (int) (maxAgeMillis / 1000) + (maxAgeMillis % 1000 != 0 ? 1 : 0);
- }
-
- public static String keepAliveHeaderValue(AsyncHttpClientConfig config) {
- return config.getAllowPoolingConnection() ? "keep-alive" : "close";
- }
-
- public static int requestTimeout(AsyncHttpClientConfig config, Request request) {
- return request.getRequestTimeoutInMs() != 0 ? request.getRequestTimeoutInMs() : config.getRequestTimeoutInMs();
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java b/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java
deleted file mode 100644
index f8957cb443..0000000000
--- a/api/src/main/java/org/asynchttpclient/util/AuthenticatorUtils.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2010-2013 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.util;
-
-import static org.asynchttpclient.util.MiscUtil.isNonEmpty;
-
-import org.asynchttpclient.ProxyServer;
-import org.asynchttpclient.Realm;
-
-import java.security.NoSuchAlgorithmException;
-
-public final class AuthenticatorUtils {
-
- public static String computeBasicAuthentication(Realm realm) {
- String s = realm.getPrincipal() + ":" + realm.getPassword();
- return "Basic " + Base64.encode(s.getBytes(realm.getCharset()));
- }
-
- public static String computeBasicAuthentication(ProxyServer proxyServer) {
- String s = proxyServer.getPrincipal() + ":" + proxyServer.getPassword();
- return "Basic " + Base64.encode(s.getBytes(proxyServer.getCharset()));
- }
-
- public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgorithmException {
-
- StringBuilder builder = new StringBuilder().append("Digest ");
- construct(builder, "username", realm.getPrincipal());
- construct(builder, "realm", realm.getRealmName());
- construct(builder, "nonce", realm.getNonce());
- construct(builder, "uri", realm.getUri());
- builder.append("algorithm").append('=').append(realm.getAlgorithm()).append(", ");
-
- construct(builder, "response", realm.getResponse());
- if (isNonEmpty(realm.getOpaque()))
- construct(builder, "opaque", realm.getOpaque());
- builder.append("qop").append('=').append(realm.getQop()).append(", ");
- builder.append("nc").append('=').append(realm.getNc()).append(", ");
- construct(builder, "cnonce", realm.getCnonce(), true);
-
- return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1));
- }
-
- public static String computeDigestAuthentication(ProxyServer proxy) {
- try {
- StringBuilder builder = new StringBuilder().append("Digest ");
- construct(builder, "username", proxy.getPrincipal(), true);
- return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1));
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- private static StringBuilder construct(StringBuilder builder, String name, String value) {
- return construct(builder, name, value, false);
- }
-
- private static StringBuilder construct(StringBuilder builder, String name, String value, boolean tail) {
- return builder.append(name).append('=').append('"').append(value).append(tail ? "\"" : "\", ");
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/util/Base64.java b/api/src/main/java/org/asynchttpclient/util/Base64.java
deleted file mode 100644
index c38ace7e39..0000000000
--- a/api/src/main/java/org/asynchttpclient/util/Base64.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.util;
-
-/**
- * Implements the "base64" binary encoding scheme as defined by
- * RFC 2045.
- *
- * Portions of code here are taken from Apache Pivot
- */
-public final class Base64 {
- private static final char[] lookup = new char[64];
- private static final byte[] reverseLookup = new byte[256];
-
- static {
- // Populate the lookup array
-
- for (int i = 0; i < 26; i++) {
- lookup[i] = (char) ('A' + i);
- }
-
- for (int i = 26, j = 0; i < 52; i++, j++) {
- lookup[i] = (char) ('a' + j);
- }
-
- for (int i = 52, j = 0; i < 62; i++, j++) {
- lookup[i] = (char) ('0' + j);
- }
-
- lookup[62] = '+';
- lookup[63] = '/';
-
- // Populate the reverse lookup array
-
- for (int i = 0; i < 256; i++) {
- reverseLookup[i] = -1;
- }
-
- for (int i = 'Z'; i >= 'A'; i--) {
- reverseLookup[i] = (byte) (i - 'A');
- }
-
- for (int i = 'z'; i >= 'a'; i--) {
- reverseLookup[i] = (byte) (i - 'a' + 26);
- }
-
- for (int i = '9'; i >= '0'; i--) {
- reverseLookup[i] = (byte) (i - '0' + 52);
- }
-
- reverseLookup['+'] = 62;
- reverseLookup['/'] = 63;
- reverseLookup['='] = 0;
- }
-
- /**
- * This class is not instantiable.
- */
- private Base64() {
- }
-
- /**
- * Encodes the specified data into a base64 string.
- *
- * @param bytes The unencoded raw data.
- */
- public static String encode(byte[] bytes) {
- // always sequence of 4 characters for each 3 bytes; padded with '='s as necessary:
- StringBuilder buf = new StringBuilder(((bytes.length + 2) / 3) * 4);
-
- // first, handle complete chunks (fast loop)
- int i = 0;
- for (int end = bytes.length - 2; i < end;) {
- int chunk = ((bytes[i++] & 0xFF) << 16) | ((bytes[i++] & 0xFF) << 8) | (bytes[i++] & 0xFF);
- buf.append(lookup[chunk >> 18]);
- buf.append(lookup[(chunk >> 12) & 0x3F]);
- buf.append(lookup[(chunk >> 6) & 0x3F]);
- buf.append(lookup[chunk & 0x3F]);
- }
-
- // then leftovers, if any
- int len = bytes.length;
- if (i < len) { // 1 or 2 extra bytes?
- int chunk = ((bytes[i++] & 0xFF) << 16);
- buf.append(lookup[chunk >> 18]);
- if (i < len) { // 2 bytes
- chunk |= ((bytes[i] & 0xFF) << 8);
- buf.append(lookup[(chunk >> 12) & 0x3F]);
- buf.append(lookup[(chunk >> 6) & 0x3F]);
- } else { // 1 byte
- buf.append(lookup[(chunk >> 12) & 0x3F]);
- buf.append('=');
- }
- buf.append('=');
- }
- return buf.toString();
- }
-
- /**
- * Decodes the specified base64 string back into its raw data.
- *
- * @param encoded The base64 encoded string.
- */
- public static byte[] decode(String encoded) {
- int padding = 0;
-
- for (int i = encoded.length() - 1; encoded.charAt(i) == '='; i--) {
- padding++;
- }
-
- int length = encoded.length() * 6 / 8 - padding;
- byte[] bytes = new byte[length];
-
- for (int i = 0, index = 0, n = encoded.length(); i < n; i += 4) {
- int word = reverseLookup[encoded.charAt(i)] << 18;
- word += reverseLookup[encoded.charAt(i + 1)] << 12;
- word += reverseLookup[encoded.charAt(i + 2)] << 6;
- word += reverseLookup[encoded.charAt(i + 3)];
-
- for (int j = 0; j < 3 && index + j < length; j++) {
- bytes[index + j] = (byte) (word >> (8 * (2 - j)));
- }
-
- index += 3;
- }
-
- return bytes;
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/util/DateUtil.java b/api/src/main/java/org/asynchttpclient/util/DateUtil.java
deleted file mode 100644
index 549174f755..0000000000
--- a/api/src/main/java/org/asynchttpclient/util/DateUtil.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.util;
-
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/util/DateUtil.java,v 1.2 2004/12/24 20:36:13 olegk Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * .
- *
- */
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * A utility class for parsing and formatting HTTP dates as used in cookies and
- * other headers. This class handles dates as defined by RFC 2616 section
- * 3.3.1 as well as some other common non-standard formats.
- *
- * @author Christopher Brown
- * @author Michael Becke
- */
-public class DateUtil {
-
- /**
- * Date format pattern used to parse HTTP date headers in RFC 1123 format.
- */
- public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
-
- /**
- * Date format pattern used to parse HTTP date headers in RFC 1036 format.
- */
- public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz";
-
- /**
- * Date format pattern used to parse HTTP date headers in ANSI C
- * asctime()
format.
- */
- public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
-
- private static final Collection DEFAULT_PATTERNS = Arrays.asList(new String[] { PATTERN_ASCTIME, PATTERN_RFC1036,
- PATTERN_RFC1123 });
-
- private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
-
- static {
- Calendar calendar = Calendar.getInstance();
- calendar.set(2000, Calendar.JANUARY, 1, 0, 0);
- DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime();
- }
-
- private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
-
- /**
- * Parses a date value. The formats used for parsing the date value are retrieved from
- * the default http params.
- *
- * @param dateValue the date value to parse
- * @return the parsed date
- * @throws DateParseException if the value could not be parsed using any of the
- * supported date formats
- */
- public static Date parseDate(String dateValue) throws DateParseException {
- return parseDate(dateValue, null, null);
- }
-
- /**
- * Parses the date value using the given date formats.
- *
- * @param dateValue the date value to parse
- * @param dateFormats the date formats to use
- * @return the parsed date
- * @throws DateParseException if none of the dataFormats could parse the dateValue
- */
- public static Date parseDate(String dateValue, Collection dateFormats) throws DateParseException {
- return parseDate(dateValue, dateFormats, null);
- }
-
- /**
- * Parses the date value using the given date formats.
- *
- * @param dateValue the date value to parse
- * @param dateFormats the date formats to use
- * @param startDate During parsing, two digit years will be placed in the range
- * startDate
to startDate + 100 years
. This value may
- * be null
. When null
is given as a parameter, year
- * 2000
will be used.
- * @return the parsed date
- * @throws DateParseException if none of the dataFormats could parse the dateValue
- */
- public static Date parseDate(String dateValue, Collection dateFormats, Date startDate) throws DateParseException {
-
- if (dateValue == null) {
- throw new IllegalArgumentException("dateValue is null");
- }
- if (dateFormats == null) {
- dateFormats = DEFAULT_PATTERNS;
- }
- if (startDate == null) {
- startDate = DEFAULT_TWO_DIGIT_YEAR_START;
- }
- // trim single quotes around date if present
- // see issue #5279
- if (dateValue.length() > 1 && dateValue.startsWith("'") && dateValue.endsWith("'")) {
- dateValue = dateValue.substring(1, dateValue.length() - 1);
- }
-
- SimpleDateFormat dateParser = null;
- Iterator formatIter = dateFormats.iterator();
-
- while (formatIter.hasNext()) {
- String format = formatIter.next();
- if (dateParser == null) {
- dateParser = new SimpleDateFormat(format, Locale.US);
- dateParser.setTimeZone(TimeZone.getTimeZone("GMT"));
- dateParser.set2DigitYearStart(startDate);
- } else {
- dateParser.applyPattern(format);
- }
- try {
- return dateParser.parse(dateValue);
- } catch (ParseException pe) {
- // ignore this exception, we will try the next format
- }
- }
-
- // we were unable to parse the date
- throw new DateParseException("Unable to parse the date " + dateValue);
- }
-
- /**
- * Formats the given date according to the RFC 1123 pattern.
- *
- * @param date The date to format.
- * @return An RFC 1123 formatted date string.
- * @see #PATTERN_RFC1123
- */
- public static String formatDate(Date date) {
- return formatDate(date, PATTERN_RFC1123);
- }
-
- /**
- * Formats the given date according to the specified pattern. The pattern
- * must conform to that used by the {@link java.text.SimpleDateFormat simple date
- * format} class.
- *
- * @param date The date to format.
- * @param pattern The pattern to use for formatting the date.
- * @return A formatted date string.
- * @throws IllegalArgumentException If the given date pattern is invalid.
- * @see java.text.SimpleDateFormat
- */
- public static String formatDate(Date date, String pattern) {
- if (date == null)
- throw new IllegalArgumentException("date is null");
- if (pattern == null)
- throw new IllegalArgumentException("pattern is null");
-
- SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US);
- formatter.setTimeZone(GMT);
- return formatter.format(date);
- }
-
- /**
- * This class should not be instantiated.
- */
- private DateUtil() {
- }
-
- public static class DateParseException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public DateParseException() {
- super();
- }
-
- /**
- * @param message the exception message
- */
- public DateParseException(String message) {
- super(message);
- }
- }
-
- public static long millisTime() {
- return System.nanoTime() / 1000000;
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java b/api/src/main/java/org/asynchttpclient/util/MiscUtil.java
deleted file mode 100644
index b65d1e4a7d..0000000000
--- a/api/src/main/java/org/asynchttpclient/util/MiscUtil.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.util;
-
-import java.util.Collection;
-import java.util.Map;
-
-public class MiscUtil {
-
- private MiscUtil() {
- }
-
- public static boolean isNonEmpty(String string) {
- return string != null && !string.isEmpty();
- }
-
- public static boolean isNonEmpty(Object[] array) {
- return array != null && array.length != 0;
- }
-
- public static boolean isNonEmpty(byte[] array) {
- return array != null && array.length != 0;
- }
-
- public static boolean isNonEmpty(Collection> collection) {
- return collection != null && !collection.isEmpty();
- }
-
- public static boolean isNonEmpty(Map, ?> map) {
- return map != null && !map.isEmpty();
- }
-}
diff --git a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java b/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java
deleted file mode 100644
index a940da8ea6..0000000000
--- a/api/src/main/java/org/asynchttpclient/util/ProxyUtils.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved.
- *
- * This program is licensed to you under the Apache License Version 2.0,
- * and you may not use this file except in compliance with the Apache License Version 2.0.
- * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the Apache License Version 2.0 is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
- */
-package org.asynchttpclient.util;
-
-import static org.asynchttpclient.util.MiscUtil.isNonEmpty;
-
-import org.asynchttpclient.AsyncHttpClientConfig;
-import org.asynchttpclient.ProxyServer;
-import org.asynchttpclient.ProxyServer.Protocol;
-import org.asynchttpclient.ProxyServerSelector;
-import org.asynchttpclient.Request;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.net.ProxySelector;
-import java.net.URI;
-import java.util.List;
-import java.util.Locale;
-import java.util.Properties;
-
-/**
- * Utilities for Proxy handling.
- *
- * @author cstamas
- */
-public class ProxyUtils {
-
- private final static Logger log = LoggerFactory.getLogger(ProxyUtils.class);
-
- private static final String PROPERTY_PREFIX = "org.asynchttpclient.AsyncHttpClientConfig.proxy.";
-
- /**
- * The host to use as proxy.
- */
- public static final String PROXY_HOST = "http.proxyHost";
-
- /**
- * The port to use for the proxy.
- */
- public static final String PROXY_PORT = "http.proxyPort";
-
- /**
- * The protocol to use. Is mapped to the {@link Protocol} enum.
- */
- public static final String PROXY_PROTOCOL = PROPERTY_PREFIX + "protocol";
-
- /**
- * A specification of non-proxy hosts. See http://download.oracle.com/javase/1.4.2/docs/guide/net/properties.html
- */
- public static final String PROXY_NONPROXYHOSTS = "http.nonProxyHosts";
-
- /**
- * The username to use for authentication for the proxy server.
- */
- public static final String PROXY_USER = PROPERTY_PREFIX + "user";
-
- /**
- * The password to use for authentication for the proxy server.
- */
- public static final String PROXY_PASSWORD = PROPERTY_PREFIX + "password";
-
- /**
- * @param config the global config
- * @param request the request
- * @return the proxy server to be used for this request (can be null)
- */
- public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request request) {
- ProxyServer proxyServer = request.getProxyServer();
- if (proxyServer == null) {
- ProxyServerSelector selector = config.getProxyServerSelector();
- if (selector != null) {
- proxyServer = selector.select(request.getOriginalURI());
- }
- }
- return ProxyUtils.avoidProxy(proxyServer, request) ? null : proxyServer;
- }
-
- /**
- * Checks whether proxy should be used according to nonProxyHosts settings of it, or we want to go directly to
- * target host. If