Skip to content

Commit 713e224

Browse files
[Java] Add HttpClient support for testing (#3011)
1 parent 7552aea commit 713e224

14 files changed

+751
-281
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
package com.microsoft.aspnet.signalr;
5+
6+
import java.io.IOException;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.Map;
10+
import java.util.concurrent.CompletableFuture;
11+
import java.util.concurrent.locks.Lock;
12+
import java.util.concurrent.locks.ReentrantLock;
13+
14+
import okhttp3.Call;
15+
import okhttp3.Callback;
16+
import okhttp3.Cookie;
17+
import okhttp3.CookieJar;
18+
import okhttp3.HttpUrl;
19+
import okhttp3.OkHttpClient;
20+
import okhttp3.Request;
21+
import okhttp3.RequestBody;
22+
import okhttp3.Response;
23+
import okhttp3.ResponseBody;
24+
25+
class DefaultHttpClient extends HttpClient {
26+
private OkHttpClient client;
27+
private Logger logger;
28+
29+
public DefaultHttpClient(Logger logger) {
30+
this.logger = logger;
31+
this.client = new OkHttpClient.Builder().cookieJar(new CookieJar() {
32+
private List<Cookie> cookieList = new ArrayList<>();
33+
private Lock cookieLock = new ReentrantLock();
34+
35+
@Override
36+
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
37+
cookieLock.lock();
38+
try {
39+
for (Cookie cookie : cookies) {
40+
boolean replacedCookie = false;
41+
for (int i = 0; i < cookieList.size(); i++) {
42+
Cookie innerCookie = cookieList.get(i);
43+
if (cookie.name().equals(innerCookie.name()) && innerCookie.matches(url)) {
44+
// We have a new cookie that matches an older one so we replace the older one.
45+
cookieList.set(i, innerCookie);
46+
replacedCookie = true;
47+
break;
48+
}
49+
}
50+
if (!replacedCookie) {
51+
cookieList.add(cookie);
52+
}
53+
}
54+
} finally {
55+
cookieLock.unlock();
56+
}
57+
}
58+
59+
@Override
60+
public List<Cookie> loadForRequest(HttpUrl url) {
61+
cookieLock.lock();
62+
try {
63+
List<Cookie> matchedCookies = new ArrayList<>();
64+
List<Cookie> expiredCookies = new ArrayList<>();
65+
for (Cookie cookie : cookieList) {
66+
if (cookie.expiresAt() < System.currentTimeMillis()) {
67+
expiredCookies.add(cookie);
68+
} else if (cookie.matches(url)) {
69+
matchedCookies.add(cookie);
70+
}
71+
}
72+
73+
cookieList.removeAll(expiredCookies);
74+
return matchedCookies;
75+
} finally {
76+
cookieLock.unlock();
77+
}
78+
}
79+
}).build();
80+
}
81+
82+
@Override
83+
public CompletableFuture<HttpResponse> send(HttpRequest httpRequest) {
84+
Request.Builder requestBuilder = new Request.Builder().url(httpRequest.getUrl());
85+
if (httpRequest.getMethod() == "GET") {
86+
requestBuilder.get();
87+
} else if (httpRequest.getMethod() == "POST") {
88+
RequestBody body = RequestBody.create(null, new byte[] {});
89+
requestBuilder.post(body);
90+
} else if (httpRequest.getMethod() == "DELETE") {
91+
requestBuilder.delete();
92+
}
93+
94+
if (httpRequest.getHeaders() != null) {
95+
httpRequest.getHeaders().forEach((key, value) -> {
96+
requestBuilder.addHeader(key, value);
97+
});
98+
}
99+
100+
Request request = requestBuilder.build();
101+
102+
CompletableFuture<HttpResponse> responseFuture = new CompletableFuture<>();
103+
104+
client.newCall(request).enqueue(new Callback() {
105+
@Override
106+
public void onFailure(Call call, IOException e) {
107+
responseFuture.completeExceptionally(e.getCause());
108+
}
109+
110+
@Override
111+
public void onResponse(Call call, Response response) throws IOException {
112+
try (ResponseBody body = response.body()) {
113+
HttpResponse httpResponse = new HttpResponse(response.code(), response.message(), body.string());
114+
responseFuture.complete(httpResponse);
115+
}
116+
}
117+
});
118+
119+
return responseFuture;
120+
}
121+
122+
@Override
123+
public WebSocketWrapper createWebSocket(String url, Map<String, String> headers) {
124+
return new OkHttpWebSocketWrapper(url, headers, client, logger);
125+
}
126+
}

clients/java/signalr/src/main/java/com/microsoft/aspnet/signalr/HandshakeProtocol.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.google.gson.Gson;
77

88
class HandshakeProtocol {
9-
public static Gson gson = new Gson();
9+
private static Gson gson = new Gson();
1010
private static final String RECORD_SEPARATOR = "\u001e";
1111

1212
public static String createHandshakeRequestMessage(HandshakeRequestMessage message) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
package com.microsoft.aspnet.signalr;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import java.util.concurrent.CompletableFuture;
9+
10+
class HttpRequest {
11+
private String method;
12+
private String url;
13+
private Map<String, String> headers = new HashMap<>();
14+
15+
public void setMethod(String method) {
16+
this.method = method;
17+
}
18+
19+
public void setUrl(String url) {
20+
this.url = url;
21+
}
22+
23+
public void setHeader(String key, String value) {
24+
this.headers.put(key, value);
25+
}
26+
27+
public void setHeaders(Map<String, String> headers) {
28+
headers.forEach((key, value) -> {
29+
this.headers.put(key, value);
30+
});
31+
}
32+
33+
public String getMethod() {
34+
return method;
35+
}
36+
37+
public String getUrl() {
38+
return url;
39+
}
40+
41+
public Map<String, String> getHeaders() {
42+
return headers;
43+
}
44+
}
45+
46+
class HttpResponse {
47+
private int statusCode;
48+
private String statusText;
49+
private String content = null;
50+
51+
public HttpResponse(int statusCode) {
52+
this.statusCode = statusCode;
53+
}
54+
55+
public HttpResponse(int statusCode, String statusText) {
56+
this.statusCode = statusCode;
57+
this.statusText = statusText;
58+
}
59+
60+
public HttpResponse(int statusCode, String statusText, String content) {
61+
this.statusCode = statusCode;
62+
this.statusText = statusText;
63+
this.content = content;
64+
}
65+
66+
public String getContent() {
67+
return content;
68+
}
69+
70+
public int getStatusCode() {
71+
return statusCode;
72+
}
73+
74+
public String getStatusText() {
75+
return statusText;
76+
}
77+
}
78+
79+
abstract class HttpClient {
80+
public CompletableFuture<HttpResponse> get(String url) {
81+
HttpRequest request = new HttpRequest();
82+
request.setUrl(url);
83+
request.setMethod("GET");
84+
return this.send(request);
85+
}
86+
87+
public CompletableFuture<HttpResponse> get(String url, HttpRequest options) {
88+
options.setUrl(url);
89+
options.setMethod("GET");
90+
return this.send(options);
91+
}
92+
93+
public CompletableFuture<HttpResponse> post(String url) {
94+
HttpRequest request = new HttpRequest();
95+
request.setUrl(url);
96+
request.setMethod("POST");
97+
return this.send(request);
98+
}
99+
100+
public CompletableFuture<HttpResponse> post(String url, HttpRequest options) {
101+
options.setUrl(url);
102+
options.setMethod("POST");
103+
return this.send(options);
104+
}
105+
106+
public CompletableFuture<HttpResponse> delete(String url) {
107+
HttpRequest request = new HttpRequest();
108+
request.setUrl(url);
109+
request.setMethod("DELETE");
110+
return this.send(request);
111+
}
112+
113+
public CompletableFuture<HttpResponse> delete(String url, HttpRequest options) {
114+
options.setUrl(url);
115+
options.setMethod("DELETE");
116+
return this.send(options);
117+
}
118+
119+
public abstract CompletableFuture<HttpResponse> send(HttpRequest request);
120+
121+
public abstract WebSocketWrapper createWebSocket(String url, Map<String, String> headers);
122+
}

0 commit comments

Comments
 (0)