Improved handling of request cancellation (classic API)
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/classic/methods/HttpExecutionAware.java b/httpclient5/src/main/java/org/apache/hc/client5/http/classic/methods/HttpExecutionAware.java
deleted file mode 100644
index ab4bb90..0000000
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/classic/methods/HttpExecutionAware.java
+++ /dev/null
@@ -1,50 +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
- * <http://www.apache.org/>.
- *
- */
-
-package org.apache.hc.client5.http.classic.methods;
-
-import org.apache.hc.core5.concurrent.Cancellable;
-
-/**
- * Interface to be implemented by any object that wishes to be notified of blocking I/O operations
- * that could be cancelled.
- *
- * @since 4.3
- */
-public interface HttpExecutionAware {
-
-    boolean isAborted();
-
-    /**
-     * Sets {@link Cancellable} for the ongoing operation.
-     *
-     * @param cancellable
-     *            {@link Cancellable} for the ongoing operation.
-     */
-    void setCancellable(Cancellable cancellable);
-
-}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/classic/methods/HttpUriRequestBase.java b/httpclient5/src/main/java/org/apache/hc/client5/http/classic/methods/HttpUriRequestBase.java
index d16716a..d6ea8b6 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/classic/methods/HttpUriRequestBase.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/classic/methods/HttpUriRequestBase.java
@@ -27,8 +27,7 @@
 package org.apache.hc.client5.http.classic.methods;
 
 import java.net.URI;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicMarkableReference;
 
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.core5.concurrent.Cancellable;
@@ -39,31 +38,31 @@
 
     private static final long serialVersionUID = 1L;
 
+    private final AtomicMarkableReference<Cancellable> cancellableRef;
     private RequestConfig requestConfig;
-    private final AtomicBoolean cancelled;
-    private final AtomicReference<Cancellable> cancellableRef;
 
     public HttpUriRequestBase(final String method, final URI requestUri) {
         super(method, requestUri);
-        this.cancelled = new AtomicBoolean(false);
-        this.cancellableRef = new AtomicReference<>(null);
+        this.cancellableRef = new AtomicMarkableReference<>(null, false);
     }
 
     @Override
     public boolean cancel() {
-        if (this.cancelled.compareAndSet(false, true)) {
-            final Cancellable cancellable = this.cancellableRef.getAndSet(null);
-            if (cancellable != null) {
-                cancellable.cancel();
+        while (!cancellableRef.isMarked()) {
+            final Cancellable actualCancellable = cancellableRef.getReference();
+            if (cancellableRef.compareAndSet(actualCancellable, actualCancellable, false, true)) {
+                if (actualCancellable != null) {
+                    actualCancellable.cancel();
+                }
+                return true;
             }
-            return true;
         }
         return false;
     }
 
     @Override
     public boolean isCancelled() {
-        return cancelled.get();
+        return cancellableRef.isMarked();
     }
 
     /**
@@ -71,8 +70,9 @@
      */
     @Override
     public void setDependency(final Cancellable cancellable) {
-        if (!this.cancelled.get()) {
-            this.cancellableRef.set(cancellable);
+        final Cancellable actualCancellable = cancellableRef.getReference();
+        if (!cancellableRef.compareAndSet(actualCancellable, cancellable, false, false)) {
+            cancellable.cancel();
         }
     }
 
@@ -82,11 +82,16 @@
      * @since 4.2
      */
     public void reset() {
-        final Cancellable cancellable = this.cancellableRef.getAndSet(null);
-        if (cancellable != null) {
-            cancellable.cancel();
+        for (;;) {
+            final boolean marked = cancellableRef.isMarked();
+            final Cancellable actualCancellable = cancellableRef.getReference();
+            if (actualCancellable != null) {
+                actualCancellable.cancel();
+            }
+            if (cancellableRef.compareAndSet(actualCancellable, null, marked, false)) {
+                break;
+            }
         }
-        this.cancelled.set(false);
     }
 
     @Override