View Javadoc

1   package com.atlassian.sal.core.net;
2   
3   
4   import com.atlassian.sal.api.net.Request;
5   import com.atlassian.sal.api.net.ResponseException;
6   import com.google.common.base.Throwables;
7   import org.apache.commons.codec.binary.Base64;
8   import org.apache.http.Header;
9   import org.apache.http.HttpClientConnection;
10  import org.apache.http.HttpEntityEnclosingRequest;
11  import org.apache.http.HttpException;
12  import org.apache.http.HttpHost;
13  import org.apache.http.HttpRequest;
14  import org.apache.http.HttpResponse;
15  import org.apache.http.HttpStatus;
16  import org.apache.http.NameValuePair;
17  import org.apache.http.ProtocolVersion;
18  import org.apache.http.auth.AUTH;
19  import org.apache.http.client.RedirectException;
20  import org.apache.http.client.config.AuthSchemes;
21  import org.apache.http.client.utils.URLEncodedUtils;
22  import org.apache.http.conn.ConnectionRequest;
23  import org.apache.http.conn.HttpClientConnectionManager;
24  import org.apache.http.conn.routing.HttpRoute;
25  import org.apache.http.entity.StringEntity;
26  import org.apache.http.message.BasicHttpResponse;
27  import org.apache.http.message.BasicNameValuePair;
28  import org.apache.http.protocol.HttpContext;
29  import org.apache.http.protocol.HttpRequestExecutor;
30  import org.hamcrest.FeatureMatcher;
31  import org.hamcrest.Matcher;
32  import org.hamcrest.Matchers;
33  import org.junit.Before;
34  import org.junit.Rule;
35  import org.junit.Test;
36  import org.junit.contrib.java.lang.system.ClearSystemProperties;
37  import org.junit.rules.ExpectedException;
38  import org.junit.runner.RunWith;
39  import org.mockito.ArgumentCaptor;
40  import org.mockito.Mock;
41  import org.mockito.invocation.InvocationOnMock;
42  import org.mockito.runners.MockitoJUnitRunner;
43  import org.mockito.stubbing.Answer;
44  
45  import java.io.IOException;
46  import java.net.URI;
47  import java.nio.charset.StandardCharsets;
48  import java.text.MessageFormat;
49  import java.util.List;
50  import java.util.concurrent.ExecutionException;
51  import java.util.concurrent.TimeUnit;
52  
53  import static org.hamcrest.CoreMatchers.instanceOf;
54  import static org.hamcrest.CoreMatchers.is;
55  import static org.hamcrest.CoreMatchers.notNullValue;
56  import static org.hamcrest.MatcherAssert.assertThat;
57  import static org.hamcrest.Matchers.arrayContaining;
58  import static org.hamcrest.Matchers.contains;
59  import static org.hamcrest.Matchers.typeCompatibleWith;
60  import static org.hamcrest.core.IsEqual.equalTo;
61  import static org.junit.Assert.fail;
62  import static org.mockito.Matchers.any;
63  import static org.mockito.Matchers.anyInt;
64  import static org.mockito.Matchers.anyObject;
65  import static org.mockito.Mockito.mock;
66  import static org.mockito.Mockito.times;
67  import static org.mockito.Mockito.verify;
68  import static org.mockito.Mockito.when;
69  
70  @RunWith(MockitoJUnitRunner.class)
71  public class TestHttpClientRequest {
72  
73      private static final String DUMMY_HOST = "dummy.atlassian.test";
74      private static final String DUMMY_HTTP_URL = MessageFormat.format("http://{0}:8090/", DUMMY_HOST);
75  
76      private static final String DUMMY_PROXY_HOST = "dummy.proxy.atlassian.test";
77      private static final String DUMMY_PROXY_PORT = "12345";
78      private static final String DUMMY_PROXY_USER = "dummyproxyuser";
79      private static final String DUMMY_PROXY_PASSWORD = "dummyproxypassword";
80  
81      @Rule
82      public ExpectedException thrown = ExpectedException.none();
83  
84      @Rule
85      public final ClearSystemProperties clearSystemProperties =
86              new ClearSystemProperties(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME,
87                      SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME,
88                      SystemPropertiesProxyConfig.PROXY_USER_PROPERTY_NAME,
89                      SystemPropertiesProxyConfig.PROXY_PASSWORD_PROPERTY_NAME,
90                      SystemPropertiesProxyConfig.PROXY_NON_HOSTS_PROPERTY_NAME);
91  
92      @Mock
93      private HttpRequestExecutor mockRequestExecutor;
94  
95      @Mock
96      private HttpClientConnectionManager mockConnectionManager;
97  
98      private HttpClientRequestFactory requestFactory;
99      private ArgumentCaptor<HttpRequest> requestCaptor = ArgumentCaptor.forClass(HttpRequest.class);
100     private ArgumentCaptor<HttpRoute> routeCaptor = ArgumentCaptor.forClass(HttpRoute.class);
101 
102     @Before
103     public void setup() throws InterruptedException, ExecutionException, IOException, HttpException {
104         requestFactory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
105 
106         // Always respond with a 200/OK message
107         when(mockRequestExecutor.execute(any(HttpRequest.class), any(HttpClientConnection.class),
108                 any(HttpContext.class))).thenReturn(createOkResponse());
109 
110         // This allows us to hook in to the connection details that HttpClient would have made
111         final HttpClientConnection conn = mock(HttpClientConnection.class);
112         final ConnectionRequest connRequest = mock(ConnectionRequest.class);
113         when(connRequest.get(anyInt(), any(TimeUnit.class))).thenReturn(conn);
114         when(mockConnectionManager.requestConnection(any(HttpRoute.class), anyObject())).thenReturn(connRequest);
115     }
116 
117     private static HttpResponse createOkResponse() {
118         final BasicHttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_OK, "OK");
119         response.setEntity(new StringEntity("test body", StandardCharsets.UTF_8));
120         return response;
121     }
122 
123     private static HttpResponse createRedirectResponse(String location) {
124         final BasicHttpResponse response = new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_MOVED_PERMANENTLY, "Redirect");
125         response.setEntity(new StringEntity("Redirect", StandardCharsets.UTF_8));
126         response.setHeader("Location", location);
127         return response;
128     }
129 
130     private static HttpResponse createNoContentResponse() {
131         return new BasicHttpResponse(new ProtocolVersion("HTTP", 1, 1), HttpStatus.SC_NO_CONTENT, "No Content");
132     }
133 
134     @Test
135     public void assertThatHeaderIsAddedToRequest() throws ResponseException, IOException, HttpException {
136         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
137 
138         final String testHeaderName = "foo";
139         final String testHeaderValue = "bar";
140         request.addHeader(testHeaderName, testHeaderValue);
141         request.execute();
142 
143         verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
144         final HttpRequest lastRequest = requestCaptor.getValue();
145         assertThat(lastRequest, notNullValue());
146 
147         final Header[] headers = lastRequest.getHeaders(testHeaderName);
148         //noinspection unchecked
149         assertThat(headers, arrayContaining(headerWithValue(equalTo(testHeaderValue))));
150     }
151 
152     @Test
153     public void testThatRouteIsNotCached() throws Exception {
154         System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, DUMMY_PROXY_HOST);
155         System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, DUMMY_PROXY_PORT);
156         final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
157 
158         HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
159         request.execute();
160 
161         System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, "hostName");
162         System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, "1234");
163 
164         request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
165         request.execute();
166 
167         verify(mockConnectionManager, times(2)).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
168         List<HttpRoute> routes = routeCaptor.getAllValues();
169         assertThat(routes.get(0), proxyHostIs(hostWithNameAndPort(DUMMY_PROXY_HOST, Integer.parseInt(DUMMY_PROXY_PORT))));
170         assertThat(routes.get(1), proxyHostIs(hostWithNameAndPort("hostName", Integer.parseInt("1234"))));
171     }
172 
173     @Test
174     public void assertThatMultiValuedHeadersAreAddedToRequest() throws ResponseException, IOException, HttpException {
175         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
176 
177         final String testHeaderName = "foo";
178         final String testHeaderValue1 = "bar1";
179         final String testHeaderValue2 = "bar2";
180         request.addHeader(testHeaderName, testHeaderValue1);
181         request.addHeader(testHeaderName, testHeaderValue2);
182         request.execute();
183 
184         verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
185         final HttpRequest lastRequest = requestCaptor.getValue();
186         assertThat(lastRequest, notNullValue());
187 
188         final Header[] headers = lastRequest.getHeaders(testHeaderName);
189         //noinspection unchecked
190         assertThat(headers, arrayContaining(
191                 headerWithValue(equalTo(testHeaderValue1)),
192                 headerWithValue(equalTo(testHeaderValue2))));
193     }
194 
195     @Test
196     public void assertThatParameterIsAddedToRequest() throws IOException, ResponseException, HttpException {
197         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.POST, DUMMY_HTTP_URL);
198 
199         final String testParameterName = "foo";
200         final String testParameterValue = "bar";
201 
202         request.addRequestParameters(testParameterName, testParameterValue);
203         request.execute();
204 
205         verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
206         final HttpRequest lastRequest = requestCaptor.getValue();
207 
208         assertThat(lastRequest, notNullValue());
209         assertThat(lastRequest.getClass(), is(typeCompatibleWith(HttpEntityEnclosingRequest.class)));
210         assertThat(lastRequest, requestParameters(contains(parameterWithNameAndValue(
211                 testParameterName, testParameterValue))));
212     }
213 
214     @Test
215     public void assertThatMultiValuedParametersAreAddedToRequest() throws IOException, ResponseException, HttpException {
216         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.POST, DUMMY_HTTP_URL);
217 
218         final String testParameterName = "foo";
219         final String testParameterValue1 = "bar1";
220         final String testParameterValue2 = "bar2";
221 
222         request.addRequestParameters(testParameterName, testParameterValue1, testParameterName, testParameterValue2);
223         request.execute();
224 
225         verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
226         final HttpRequest lastRequest = requestCaptor.getValue();
227 
228         assertThat(lastRequest, notNullValue());
229         assertThat(lastRequest.getClass(), is(typeCompatibleWith(HttpEntityEnclosingRequest.class)));
230         //noinspection unchecked
231         assertThat(lastRequest, requestParameters(contains(
232                 parameterWithNameAndValue(testParameterName, testParameterValue1),
233                 parameterWithNameAndValue(testParameterName, testParameterValue2)
234         )));
235     }
236 
237     @Test
238     public void assertThatParametersAreAddedWithMultipleCalls() throws IOException, ResponseException, HttpException {
239         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.POST, DUMMY_HTTP_URL);
240 
241         final String testParameterName = "foo";
242         final String testParameterValue1 = "bar1";
243         final String testParameterValue2 = "bar2";
244 
245         request.addRequestParameters(testParameterName, testParameterValue1);
246         request.addRequestParameters(testParameterName, testParameterValue2);
247         request.execute();
248 
249         verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
250         final HttpRequest lastRequest = requestCaptor.getValue();
251 
252         assertThat(lastRequest, notNullValue());
253         assertThat(lastRequest.getClass(), is(typeCompatibleWith(HttpEntityEnclosingRequest.class)));
254         //noinspection unchecked
255         assertThat(lastRequest, requestParameters(contains(
256                 parameterWithNameAndValue(testParameterName, testParameterValue1),
257                 parameterWithNameAndValue(testParameterName, testParameterValue2)
258         )));
259     }
260 
261     @Test
262     public void assertThatAddingParametersToGetRequestThrowsException() {
263         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
264         thrown.expect(IllegalStateException.class);
265         request.addRequestParameters("foo", "bar");
266     }
267 
268     @Test
269     public void assertThatSystemProxyHostSettingHonoured() throws IOException, ResponseException, HttpException {
270         System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, DUMMY_PROXY_HOST);
271         System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, DUMMY_PROXY_PORT);
272 
273         final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
274         final HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
275         request.execute();
276 
277         verify(mockConnectionManager).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
278         HttpRoute route = routeCaptor.getValue();
279         assertThat(route, proxyHostIs(hostWithNameAndPort(DUMMY_PROXY_HOST, Integer.parseInt(DUMMY_PROXY_PORT))));
280     }
281 
282     @Test
283     public void assertThatProxyNotUsedByDefault() throws IOException, ResponseException, HttpException {
284         final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
285         final HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
286         request.execute();
287 
288         verify(mockConnectionManager).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
289         final HttpRoute route = routeCaptor.getValue();
290         assertThat(route, proxyHostIs(Matchers.nullValue(HttpHost.class)));
291     }
292 
293     @Test
294     public void assertThatNonProxyHostsSystemPropertyHonoured() throws IOException, ResponseException, HttpException {
295         System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, DUMMY_PROXY_HOST);
296         System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, DUMMY_PROXY_PORT);
297         System.setProperty(SystemPropertiesProxyConfig.PROXY_NON_HOSTS_PROPERTY_NAME, "*.notproxied.test|localhost");
298 
299         final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
300         final HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
301 
302         request.execute();
303         request.setUrl("http://www.notproxied.test").execute();
304 
305         verify(mockConnectionManager, times(2)).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
306 
307         final List<HttpRoute> routes = routeCaptor.getAllValues();
308 
309         //noinspection unchecked
310         assertThat(routes, contains(
311                 proxyHostIs(hostWithNameAndPort(DUMMY_PROXY_HOST, Integer.parseInt(DUMMY_PROXY_PORT))),
312                 proxyHostIs(Matchers.nullValue(HttpHost.class))
313         ));
314     }
315 
316     @Test
317     public void assertThatProxyAuthenticationSystemPropertyHonoured() throws IOException, ResponseException, HttpException {
318         System.setProperty(SystemPropertiesProxyConfig.PROXY_HOST_PROPERTY_NAME, DUMMY_PROXY_HOST);
319         System.setProperty(SystemPropertiesProxyConfig.PROXY_PORT_PROPERTY_NAME, DUMMY_PROXY_PORT);
320         System.setProperty(SystemPropertiesProxyConfig.PROXY_USER_PROPERTY_NAME, DUMMY_PROXY_USER);
321         System.setProperty(SystemPropertiesProxyConfig.PROXY_PASSWORD_PROPERTY_NAME, DUMMY_PROXY_PASSWORD);
322 
323         final HttpClientRequestFactory factory = new HttpClientWithMockConnectionRequestFactory(mockConnectionManager, mockRequestExecutor);
324         final HttpClientRequest request = factory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
325         final String username = "charlie";
326         final String password = "password123";
327         request.addBasicAuthentication(DUMMY_HOST, username, password);
328         request.execute();
329         verify(mockConnectionManager).connect(any(HttpClientConnection.class), routeCaptor.capture(), anyInt(), any(HttpContext.class));
330         final HttpRoute route = routeCaptor.getValue();
331         assertThat(route, proxyHostIs(hostWithNameAndPort(DUMMY_PROXY_HOST, Integer.parseInt(DUMMY_PROXY_PORT))));
332 
333         verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
334         final HttpRequest lastRequest = requestCaptor.getValue();
335         final Header[] headers = lastRequest.getHeaders(AUTH.PROXY_AUTH_RESP);
336 
337         //noinspection unchecked
338         assertThat(headers, arrayContaining(headerWithValue(
339                 basicAuthWithUsernameAndPassword(DUMMY_PROXY_USER, DUMMY_PROXY_PASSWORD))));
340     }
341 
342     private void assertThatBasicAuthenticationHeadersAdded(String url) throws Exception {
343         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, url);
344 
345         final String username = "charlie";
346         final String password = "password123";
347         final URI uri = new URI(url);
348         request.addBasicAuthentication(uri.getHost(), username, password);
349         request.execute();
350 
351         verify(mockRequestExecutor).execute(requestCaptor.capture(), any(HttpClientConnection.class), any(HttpContext.class));
352         final HttpRequest lastRequest = requestCaptor.getValue();
353         final Header[] headers = lastRequest.getHeaders(AUTH.WWW_AUTH_RESP);
354 
355         //noinspection unchecked
356         assertThat(headers, arrayContaining(headerWithValue(basicAuthWithUsernameAndPassword(username, password))));
357     }
358 
359     @Test
360     public void assertThatBasicAuthenticationHeadersAddedDefaultPort() throws Exception {
361         assertThatBasicAuthenticationHeadersAdded(MessageFormat.format("http://{0}/", DUMMY_HOST));
362     }
363 
364     @Test
365     public void assertThatBasicAuthenticationHeadersAddedNotDefaultPort() throws Exception {
366         assertThatBasicAuthenticationHeadersAdded(MessageFormat.format("http://{0}:8090/", DUMMY_HOST));
367     }
368 
369     @Test
370     public void assertThatBasicAuthenticationHeadersAddedForHttpsNotDefaultPort() throws Exception {
371         assertThatBasicAuthenticationHeadersAdded(MessageFormat.format("https://{0}:8090/", DUMMY_HOST));
372     }
373 
374     @Test
375     public void assertThatBasicAuthenticationHeadersAddedForHttpsDefaultPort() throws Exception {
376         assertThatBasicAuthenticationHeadersAdded(MessageFormat.format("https://{0}/", DUMMY_HOST));
377     }
378 
379     @Test
380     public void assertThatExceptionThrownAfterDefaultMaximumRedirects() throws ResponseException, IOException, HttpException {
381 
382         when(mockRequestExecutor.execute(any(HttpRequest.class), any(HttpClientConnection.class),
383                 any(HttpContext.class))).thenAnswer(new Answer<HttpResponse>() {
384             int redirectCount = 0;
385 
386             @Override
387             public HttpResponse answer(final InvocationOnMock invocationOnMock) throws Throwable {
388                 // We just add a changing query string parameter here to avoid a circular redirect
389                 return createRedirectResponse(DUMMY_HTTP_URL + "?redirect_count=" + redirectCount++);
390             }
391         });
392 
393         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
394 
395         try {
396             request.execute();
397             fail("An exception should be thrown when maximum redirects is exceeded.");
398         } catch (ResponseException expectedException) {
399             // Although JUnit has an ExpectedException rule, we need to catch this both to ensure that a
400             // RedirectException is the cause, and to subsequently verify the execution method call count.
401             assertThat(Throwables.getCausalChain(expectedException), Matchers.<Throwable>hasItem(instanceOf(RedirectException.class)));
402         }
403 
404         verify(mockRequestExecutor, times(SystemPropertiesConnectionConfig.DEFAULT_MAX_REDIRECTS + 1))
405                 .execute(any(HttpRequest.class), any(HttpClientConnection.class), any(HttpContext.class));
406     }
407 
408     @Test
409     public void assertThatNoContentDoesNotThrowNPE() throws ResponseException, IOException, HttpException {
410         when(mockRequestExecutor.execute(any(HttpRequest.class), any(HttpClientConnection.class),
411                 any(HttpContext.class))).thenAnswer(new Answer<HttpResponse>() {
412             @Override
413             public HttpResponse answer(final InvocationOnMock invocationOnMock) throws Throwable {
414                 return createNoContentResponse();
415             }
416         });
417         final HttpClientRequest request = requestFactory.createRequest(Request.MethodType.GET, DUMMY_HTTP_URL);
418         request.execute();
419     }
420 
421     private static Matcher<Header> headerWithValue(final Matcher<String> valueMatcher) {
422         return new FeatureMatcher<Header, String>(valueMatcher, "header with value", "header value") {
423             @Override
424             protected String featureValueOf(final Header header) {
425                 return header.getValue();
426             }
427         };
428     }
429 
430     private static Matcher<HttpRequest> requestParameters(final Matcher<Iterable<? extends NameValuePair>> parametersMatcher) {
431         return new FeatureMatcher<HttpRequest, Iterable<? extends NameValuePair>>(
432                 parametersMatcher, "parameters with value", "parameters value") {
433             @Override
434             protected Iterable<? extends NameValuePair> featureValueOf(final HttpRequest httpRequest) {
435                 try {
436                     return URLEncodedUtils.parse(((HttpEntityEnclosingRequest) httpRequest).getEntity());
437                 } catch (IOException e) {
438                     throw new RuntimeException(e);
439                 }
440             }
441         };
442     }
443 
444     private static Matcher<NameValuePair> parameterWithNameAndValue(final String name, final String value) {
445 
446         final NameValuePair expectedParameter = new BasicNameValuePair(name, value);
447         return Matchers.equalTo(expectedParameter);
448     }
449 
450     private static Matcher<HttpRoute> proxyHostIs(final Matcher<HttpHost> routeMatcher) {
451         return new FeatureMatcher<HttpRoute, HttpHost>(routeMatcher, "proxy host for route", "proxy host") {
452             @Override
453             protected HttpHost featureValueOf(final HttpRoute route) {
454                 return route.getProxyHost();
455             }
456         };
457     }
458 
459     private static Matcher<HttpHost> hostWithNameAndPort(final String name, final int port) {
460 
461         final HttpHost expectedHost = new HttpHost(name, port);
462         return Matchers.equalTo(expectedHost);
463     }
464 
465     private static Matcher<String> basicAuthWithUsernameAndPassword(final String username, final String password) {
466 
467         final String basicAuthCreds = MessageFormat.format("{0}:{1}", username, password);
468         final String encodedBasicAuthCreds = Base64.encodeBase64String(basicAuthCreds.getBytes());
469         final String expectedBasicAuthHeader = MessageFormat.format("{0} {1}", AuthSchemes.BASIC, encodedBasicAuthCreds);
470 
471         return Matchers.equalTo(expectedBasicAuthHeader);
472     }
473 
474 }