1 package org.robolectric.shadows.httpclient; 2 3 import com.google.errorprone.annotations.InlineMe; 4 import java.io.ByteArrayInputStream; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.lang.reflect.Field; 8 import org.apache.commons.logging.Log; 9 import org.apache.commons.logging.LogFactory; 10 import org.apache.http.ConnectionReuseStrategy; 11 import org.apache.http.HttpEntity; 12 import org.apache.http.HttpException; 13 import org.apache.http.HttpHost; 14 import org.apache.http.HttpRequest; 15 import org.apache.http.HttpResponse; 16 import org.apache.http.client.AuthenticationHandler; 17 import org.apache.http.client.HttpRequestRetryHandler; 18 import org.apache.http.client.RedirectHandler; 19 import org.apache.http.client.UserTokenHandler; 20 import org.apache.http.conn.ClientConnectionManager; 21 import org.apache.http.conn.ConnectionKeepAliveStrategy; 22 import org.apache.http.conn.routing.HttpRoutePlanner; 23 import org.apache.http.entity.BasicHttpEntity; 24 import org.apache.http.entity.HttpEntityWrapper; 25 import org.apache.http.impl.client.DefaultRequestDirector; 26 import org.apache.http.params.HttpParams; 27 import org.apache.http.protocol.HttpContext; 28 import org.apache.http.protocol.HttpProcessor; 29 import org.apache.http.protocol.HttpRequestExecutor; 30 import org.robolectric.annotation.Implementation; 31 import org.robolectric.annotation.Implements; 32 import org.robolectric.annotation.RealObject; 33 import org.robolectric.annotation.Resetter; 34 import org.robolectric.util.Util; 35 36 @SuppressWarnings({"UnusedDeclaration"}) 37 @Implements(DefaultRequestDirector.class) 38 public class ShadowDefaultRequestDirector { 39 @RealObject DefaultRequestDirector realObject; 40 41 protected Log log; 42 protected ClientConnectionManager connectionManager; 43 protected HttpRoutePlanner httpRoutePlanner; 44 protected ConnectionReuseStrategy connectionReuseStrategy; 45 protected ConnectionKeepAliveStrategy connectionKeepAliveStrategy; 46 protected HttpRequestExecutor httpRequestExecutor; 47 protected HttpProcessor httpProcessor; 48 protected HttpRequestRetryHandler httpRequestRetryHandler; 49 protected RedirectHandler redirectHandler; 50 protected AuthenticationHandler targetAuthenticationHandler; 51 protected AuthenticationHandler proxyAuthenticationHandler; 52 protected UserTokenHandler userTokenHandler; 53 protected HttpParams httpParams; 54 55 org.robolectric.shadows.httpclient.DefaultRequestDirector redirector; 56 57 @Implementation __constructor__( Log log, HttpRequestExecutor requestExec, ClientConnectionManager conman, ConnectionReuseStrategy reustrat, ConnectionKeepAliveStrategy kastrat, HttpRoutePlanner rouplan, HttpProcessor httpProcessor, HttpRequestRetryHandler retryHandler, RedirectHandler redirectHandler, AuthenticationHandler targetAuthHandler, AuthenticationHandler proxyAuthHandler, UserTokenHandler userTokenHandler, HttpParams params)58 protected void __constructor__( 59 Log log, 60 HttpRequestExecutor requestExec, 61 ClientConnectionManager conman, 62 ConnectionReuseStrategy reustrat, 63 ConnectionKeepAliveStrategy kastrat, 64 HttpRoutePlanner rouplan, 65 HttpProcessor httpProcessor, 66 HttpRequestRetryHandler retryHandler, 67 RedirectHandler redirectHandler, 68 AuthenticationHandler targetAuthHandler, 69 AuthenticationHandler proxyAuthHandler, 70 UserTokenHandler userTokenHandler, 71 HttpParams params) { 72 this.log = log; 73 this.httpRequestExecutor = requestExec; 74 this.connectionManager = conman; 75 this.connectionReuseStrategy = reustrat; 76 this.connectionKeepAliveStrategy = kastrat; 77 this.httpRoutePlanner = rouplan; 78 this.httpProcessor = httpProcessor; 79 this.httpRequestRetryHandler = retryHandler; 80 this.redirectHandler = redirectHandler; 81 this.targetAuthenticationHandler = targetAuthHandler; 82 this.proxyAuthenticationHandler = proxyAuthHandler; 83 this.userTokenHandler = userTokenHandler; 84 this.httpParams = params; 85 86 try { 87 redirector = 88 new org.robolectric.shadows.httpclient.DefaultRequestDirector( 89 log, 90 requestExec, 91 conman, 92 reustrat, 93 kastrat, 94 rouplan, 95 httpProcessor, 96 retryHandler, 97 redirectHandler, 98 targetAuthHandler, 99 proxyAuthHandler, 100 userTokenHandler, 101 params); 102 } catch (IllegalArgumentException ignored) { 103 FakeHttp.getFakeHttpLayer().interceptHttpRequests(true); 104 } 105 } 106 107 @Implementation __constructor__( HttpRequestExecutor requestExec, ClientConnectionManager conman, ConnectionReuseStrategy reustrat, ConnectionKeepAliveStrategy kastrat, HttpRoutePlanner rouplan, HttpProcessor httpProcessor, HttpRequestRetryHandler retryHandler, RedirectHandler redirectHandler, AuthenticationHandler targetAuthHandler, AuthenticationHandler proxyAuthHandler, UserTokenHandler userTokenHandler, HttpParams params)108 protected void __constructor__( 109 HttpRequestExecutor requestExec, 110 ClientConnectionManager conman, 111 ConnectionReuseStrategy reustrat, 112 ConnectionKeepAliveStrategy kastrat, 113 HttpRoutePlanner rouplan, 114 HttpProcessor httpProcessor, 115 HttpRequestRetryHandler retryHandler, 116 RedirectHandler redirectHandler, 117 AuthenticationHandler targetAuthHandler, 118 AuthenticationHandler proxyAuthHandler, 119 UserTokenHandler userTokenHandler, 120 HttpParams params) { 121 __constructor__( 122 LogFactory.getLog(DefaultRequestDirector.class), 123 requestExec, 124 conman, 125 reustrat, 126 kastrat, 127 rouplan, 128 httpProcessor, 129 retryHandler, 130 redirectHandler, 131 targetAuthHandler, 132 proxyAuthHandler, 133 userTokenHandler, 134 params); 135 } 136 137 /** 138 * Get the sent {@link HttpRequest} for the given index. 139 * 140 * @param index The index 141 * @deprecated Use {@link FakeHttp#getSentHttpRequestInfo(int)} instead. This method will be 142 * removed in Robolectric 4.13. 143 * @return HttpRequest 144 */ 145 @Deprecated 146 @InlineMe( 147 replacement = "FakeHttp.getFakeHttpLayer().getSentHttpRequestInfo(index).getHttpRequest()", 148 imports = "org.robolectric.shadows.httpclient.FakeHttp") getSentHttpRequest(int index)149 public static HttpRequest getSentHttpRequest(int index) { 150 return FakeHttp.getFakeHttpLayer().getSentHttpRequestInfo(index).getHttpRequest(); 151 } 152 getLatestSentHttpRequest()153 public static HttpRequest getLatestSentHttpRequest() { 154 return getLatestSentHttpRequestInfo().getHttpRequest(); 155 } 156 getLatestSentHttpRequestInfo()157 public static HttpRequestInfo getLatestSentHttpRequestInfo() { 158 int requestCount = FakeHttp.getFakeHttpLayer().getSentHttpRequestInfos().size(); 159 return FakeHttp.getFakeHttpLayer().getSentHttpRequestInfo(requestCount - 1); 160 } 161 162 /** 163 * Get the sent {@link HttpRequestInfo} for the given index. 164 * 165 * @param index The index 166 * @deprecated Use {@link FakeHttp#getSentHttpRequest(int)} instead. This method will be removed 167 * in Robolectric 4.13. 168 * @return HttpRequestInfo 169 */ 170 @Deprecated 171 @InlineMe( 172 replacement = "FakeHttp.getFakeHttpLayer().getSentHttpRequestInfo(index)", 173 imports = "org.robolectric.shadows.httpclient.FakeHttp") getSentHttpRequestInfo(int index)174 public static HttpRequestInfo getSentHttpRequestInfo(int index) { 175 return FakeHttp.getFakeHttpLayer().getSentHttpRequestInfo(index); 176 } 177 178 @Implementation execute( HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext)179 protected HttpResponse execute( 180 HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) 181 throws HttpException, IOException { 182 if (FakeHttp.getFakeHttpLayer().isInterceptingHttpRequests()) { 183 return FakeHttp.getFakeHttpLayer() 184 .emulateRequest(httpHost, httpRequest, httpContext, realObject); 185 } else { 186 FakeHttp.getFakeHttpLayer() 187 .addRequestInfo(new HttpRequestInfo(httpRequest, httpHost, httpContext, redirector)); 188 HttpResponse response = redirector.execute(httpHost, httpRequest, httpContext); 189 190 if (FakeHttp.getFakeHttpLayer().isInterceptingResponseContent()) { 191 interceptResponseContent(response); 192 } 193 194 FakeHttp.getFakeHttpLayer().addHttpResponse(response); 195 return response; 196 } 197 } 198 getLog()199 public Log getLog() { 200 return log; 201 } 202 getConnectionManager()203 public ClientConnectionManager getConnectionManager() { 204 return connectionManager; 205 } 206 getHttpRoutePlanner()207 public HttpRoutePlanner getHttpRoutePlanner() { 208 return httpRoutePlanner; 209 } 210 getConnectionReuseStrategy()211 public ConnectionReuseStrategy getConnectionReuseStrategy() { 212 return connectionReuseStrategy; 213 } 214 getConnectionKeepAliveStrategy()215 public ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() { 216 return connectionKeepAliveStrategy; 217 } 218 getHttpRequestExecutor()219 public HttpRequestExecutor getHttpRequestExecutor() { 220 return httpRequestExecutor; 221 } 222 getHttpProcessor()223 public HttpProcessor getHttpProcessor() { 224 return httpProcessor; 225 } 226 getHttpRequestRetryHandler()227 public HttpRequestRetryHandler getHttpRequestRetryHandler() { 228 return httpRequestRetryHandler; 229 } 230 getRedirectHandler()231 public RedirectHandler getRedirectHandler() { 232 return redirectHandler; 233 } 234 getTargetAuthenticationHandler()235 public AuthenticationHandler getTargetAuthenticationHandler() { 236 return targetAuthenticationHandler; 237 } 238 getProxyAuthenticationHandler()239 public AuthenticationHandler getProxyAuthenticationHandler() { 240 return proxyAuthenticationHandler; 241 } 242 getUserTokenHandler()243 public UserTokenHandler getUserTokenHandler() { 244 return userTokenHandler; 245 } 246 getHttpParams()247 public HttpParams getHttpParams() { 248 return httpParams; 249 } 250 251 @Resetter reset()252 public static void reset() { 253 FakeHttp.reset(); 254 } 255 interceptResponseContent(HttpResponse response)256 private void interceptResponseContent(HttpResponse response) { 257 HttpEntity entity = response.getEntity(); 258 if (entity instanceof HttpEntityWrapper) { 259 HttpEntityWrapper entityWrapper = (HttpEntityWrapper) entity; 260 try { 261 Field wrappedEntity = HttpEntityWrapper.class.getDeclaredField("wrappedEntity"); 262 wrappedEntity.setAccessible(true); 263 entity = (HttpEntity) wrappedEntity.get(entityWrapper); 264 } catch (Exception e) { 265 // fail to record 266 } 267 } 268 if (entity instanceof BasicHttpEntity) { 269 BasicHttpEntity basicEntity = (BasicHttpEntity) entity; 270 try { 271 Field contentField = BasicHttpEntity.class.getDeclaredField("content"); 272 contentField.setAccessible(true); 273 InputStream content = (InputStream) contentField.get(basicEntity); 274 275 byte[] buffer = Util.readBytes(content); 276 277 FakeHttp.getFakeHttpLayer().addHttpResponseContent(buffer); 278 contentField.set(basicEntity, new ByteArrayInputStream(buffer)); 279 } catch (Exception e) { 280 // fail to record 281 } 282 } 283 } 284 } 285