dateFormats, Date startDate) {
88 |
89 | // trim single quotes around date if present
90 | // see issue #5279
91 | if (dateValue.length() > 1 && dateValue.startsWith("'") && dateValue.endsWith("'")) {
92 | dateValue = dateValue.substring(1, dateValue.length() - 1);
93 | }
94 |
95 | SimpleDateFormat dateParser = null;
96 | for (String format : dateFormats) {
97 | if (dateParser == null) {
98 | dateParser = new SimpleDateFormat(format, Locale.US);
99 | dateParser.setTimeZone(TimeZone.getTimeZone("GMT"));
100 | dateParser.set2DigitYearStart(startDate);
101 | } else {
102 | dateParser.applyPattern(format);
103 | }
104 | try {
105 | return dateParser.parse(dateValue);
106 | } catch (ParseException pe) {
107 | // ignore this exception, we will try the next format
108 | }
109 | }
110 |
111 | // we were unable to parse the date
112 | return null;
113 | }
114 |
115 | /**
116 | * Formats the given date according to the RFC 1123 pattern.
117 | *
118 | * @param date The date to format.
119 | * @return An RFC 1123 formatted date string.
120 | * @see #PATTERN_RFC1123
121 | */
122 | public static String formatDate(Date date) {
123 | return formatDate(date, PATTERN_RFC1123);
124 | }
125 |
126 | /**
127 | * Formats the given date according to the specified pattern. The pattern
128 | * must conform to that used by the {@link SimpleDateFormat simple date
129 | * format} class.
130 | *
131 | * @param date The date to format.
132 | * @param pattern The pattern to use for formatting the date.
133 | * @return A formatted date string.
134 | * @throws IllegalArgumentException If the given date pattern is invalid.
135 | * @see SimpleDateFormat
136 | */
137 | public static String formatDate(Date date, String pattern) {
138 | SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US);
139 | formatter.setTimeZone(GMT);
140 | return formatter.format(date);
141 | }
142 |
143 | }
--------------------------------------------------------------------------------
/src/main/java/me/gv7/woodpecker/requests/utils/Cookies.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.utils;
2 |
3 | import me.gv7.woodpecker.requests.Cookie;
4 | import me.gv7.woodpecker.requests.Parameter;
5 | import org.checkerframework.checker.nullness.qual.Nullable;
6 |
7 | import java.util.Date;
8 |
9 | /**
10 | * Only for internal use.
11 | * Http response set cookie header.
12 | *
13 | * RFC 6265:
14 | * The origin domain of a cookie is the domain of the originating request.
15 | * If the origin domain is an IP, the cookie's domain attribute must not be set.
16 | * If a cookie's domain attribute is not set, the cookie is only applicable to its origin domain.
17 | * If a cookie's domain attribute is set,
18 | * -- the cookie is applicable to that domain and all its subdomains;
19 | * -- the cookie's domain must be the same as, or a parent of, the origin domain
20 | * -- the cookie's domain must not be a TLD, a public suffix, or a parent of a public suffix.
21 | */
22 | public class Cookies {
23 |
24 | /**
25 | * Get cookie default path from url path
26 | */
27 | public static String calculatePath(String uri) {
28 | if (!uri.startsWith("/")) {
29 | return "/";
30 | }
31 | int idx = uri.lastIndexOf('/');
32 | return uri.substring(0, idx + 1);
33 | }
34 |
35 | /**
36 | * A simple, non-accurate method(we just need to distinguish ip and domain) to judge if host is a ipv4/ipv6 address.
37 | */
38 | public static boolean isIP(String host) {
39 | return isIPV4(host) || isIPV6(host);
40 | }
41 |
42 |
43 | private static boolean isIPV4(String host) {
44 | int dotCount = 0;
45 | for (int i = 0; i < host.length(); i++) {
46 | char c = host.charAt(i);
47 | if (c >= '0' && c <= '9') {
48 | //
49 | } else if (c == '.') {
50 | if (++dotCount > 3) {
51 | return false;
52 | }
53 | } else {
54 | return false;
55 | }
56 | }
57 | return true;
58 | }
59 |
60 | private static boolean isIPV6(String host) {
61 | int colonCount = 0;
62 | int dotCount = 0;
63 | for (int i = 0; i < host.length(); i++) {
64 | char c = host.charAt(i);
65 | if (c >= '0' && c <= '9') {
66 | //
67 | } else if (c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F') {
68 | if (dotCount > 0) {
69 | return false;
70 | }
71 | } else if (c == ':') {
72 | colonCount++;
73 | if (colonCount + dotCount > 7) {
74 | return false;
75 | }
76 | } else if (c == '.') {
77 | dotCount++;
78 | if (colonCount < 2 || dotCount > 3) {
79 | return false;
80 | }
81 | } else {
82 | return false;
83 | }
84 | }
85 | return true;
86 | }
87 |
88 |
89 | /**
90 | * If domainSuffix is suffix of domain
91 | *
92 | * @param domain start with "."
93 | * @param domainSuffix not start with "."
94 | */
95 | public static boolean isDomainSuffix(String domain, String domainSuffix) {
96 | if (domain.length() < domainSuffix.length()) {
97 | return false;
98 | }
99 | if (domain.length() == domainSuffix.length()) {
100 | return domain.equals(domainSuffix);
101 | }
102 |
103 | return domain.endsWith(domainSuffix) && domain.charAt(domain.length() - domainSuffix.length() - 1) == '.';
104 | }
105 |
106 |
107 | /**
108 | * If cookie match the given scheme, host, and path.
109 | *
110 | * @param host should be lower case
111 | */
112 | public static boolean match(Cookie cookie, String protocol, String host, String path) {
113 | if (cookie.secure() && !protocol.equalsIgnoreCase("https")) {
114 | return false;
115 | }
116 |
117 | // check domain
118 | if (isIP(host) || cookie.hostOnly()) {
119 | if (!host.equals(cookie.domain())) {
120 | return false;
121 | }
122 | } else {
123 | if (!Cookies.isDomainSuffix(host, cookie.domain())) {
124 | return false;
125 | }
126 | }
127 |
128 | String cookiePath = cookie.path();
129 | // check path
130 | if (cookiePath.length() > path.length()) {
131 | return false;
132 | }
133 | if (cookiePath.length() == path.length()) {
134 | return cookiePath.equals(path);
135 | }
136 | if (!path.startsWith(cookiePath)) {
137 | return false;
138 | }
139 | if (cookiePath.charAt(cookiePath.length() - 1) != '/' && path.charAt(cookiePath.length()) != '/') {
140 | return false;
141 | }
142 | return true;
143 | }
144 |
145 | /**
146 | * Parse one cookie header value, return the cookie.
147 | *
148 | * @param host should be lower case
149 | * @return return null means is not a valid cookie str.
150 | */
151 | @Nullable
152 | public static Cookie parseCookie(String cookieStr, String host, String defaultPath) {
153 | String[] items = cookieStr.split(";");
154 | Parameter param = parseCookieNameValue(items[0]);
155 | if (param == null) {
156 | return null;
157 | }
158 |
159 | String domain = "";
160 | String path = "";
161 | long expiry = 0;
162 | boolean secure = false;
163 | for (String item : items) {
164 | item = item.trim();
165 | if (item.isEmpty()) {
166 | continue;
167 | }
168 | Parameter attribute = parseCookieAttribute(item);
169 | switch (attribute.name().toLowerCase()) {
170 | case "domain":
171 | domain = normalizeDomain(attribute.value());
172 | break;
173 | case "path":
174 | path = normalizePath(attribute.value());
175 | break;
176 | case "expires":
177 | // If a cookie has both the Max-Age and the Expires attribute, the Max-Age attribute has precedence
178 | // and controls the expiration date of the cookie.
179 | if (expiry == 0) {
180 | Date date = CookieDateUtil.parseDate(attribute.value());
181 | if (date != null) {
182 | expiry = date.getTime();
183 | if (expiry == 0) {
184 | expiry = 1;
185 | }
186 | }
187 | }
188 | break;
189 | case "max-age":
190 | try {
191 | int seconds = Integer.parseInt(attribute.value());
192 | expiry = System.currentTimeMillis() + seconds * 1000;
193 | if (expiry == 0) {
194 | expiry = 1;
195 | }
196 | } catch (NumberFormatException ignore) {
197 | }
198 | break;
199 | case "secure":
200 | secure = true;
201 | break;
202 | case "httponly":
203 | // ignore http only now
204 | break;
205 | default:
206 | }
207 | }
208 |
209 | if (path.isEmpty()) {
210 | path = defaultPath;
211 | }
212 | boolean hostOnly;
213 | if (domain.isEmpty()) {
214 | domain = host;
215 | hostOnly = true;
216 | } else {
217 | if (isIP(host)) {
218 | // should not set
219 | return null;
220 | }
221 | if (!isDomainSuffix(host, domain)) {
222 | return null;
223 | }
224 | hostOnly = false;
225 | }
226 |
227 | return new Cookie(domain, path, param.name(), param.value(), expiry, secure, hostOnly);
228 | }
229 |
230 |
231 | @Nullable
232 | private static Parameter parseCookieNameValue(String str) {
233 | // Browsers always split the name and value on the first = symbol in the string
234 | int idx = str.indexOf("=");
235 | if (idx <= 0) {
236 | // If there is no = symbol in the string at all, RFC 6265 ignore this cookie.
237 | // if cookie name is empty, RFC 6265 ignore this cookie.
238 | return null;
239 | }
240 | return Parameter.of(str.substring(0, idx).trim(), str.substring(idx + 1).trim());
241 | }
242 |
243 | private static Parameter parseCookieAttribute(String str) {
244 | int idx = str.indexOf("=");
245 | if (idx < 0) {
246 | return Parameter.of(str, "");
247 | } else {
248 | return Parameter.of(str.substring(0, idx), str.substring(idx + 1));
249 | }
250 | }
251 |
252 | private static String normalizePath(String str) {
253 | if (!str.startsWith("/")) {
254 | // use defaultPath
255 | return "";
256 | }
257 | return str;
258 | }
259 |
260 | /**
261 | * Parse cookie domain.
262 | * In RFC 6265, the leading dot will be ignored, and cookie always available in sub domains.
263 | *
264 | * @return the final domain
265 | */
266 | private static String normalizeDomain(String value) {
267 | if (value.startsWith(".")) {
268 | return value.substring(1);
269 | }
270 | return value.toLowerCase();
271 | }
272 | }
273 |
--------------------------------------------------------------------------------
/src/main/java/me/gv7/woodpecker/requests/utils/NopHostnameVerifier.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.utils;
2 |
3 | import javax.net.ssl.HostnameVerifier;
4 | import javax.net.ssl.SSLSession;
5 |
6 | /**
7 | * @author Liu Dong
8 | */
9 | public class NopHostnameVerifier implements HostnameVerifier {
10 |
11 | private static class Holder {
12 | private static NopHostnameVerifier instance = new NopHostnameVerifier();
13 | }
14 |
15 | public static HostnameVerifier getInstance() {
16 | return Holder.instance;
17 | }
18 |
19 | @Override
20 | public boolean verify(String s, SSLSession sslSession) {
21 | return true;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/me/gv7/woodpecker/requests/utils/SSLSocketFactories.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.utils;
2 |
3 | import me.gv7.woodpecker.requests.exception.TrustManagerLoadFailedException;
4 | import me.gv7.woodpecker.requests.exception.RequestsException;
5 |
6 | import javax.net.ssl.*;
7 | import java.security.*;
8 | import java.security.cert.CertificateException;
9 | import java.security.cert.X509Certificate;
10 | import java.util.concurrent.ConcurrentHashMap;
11 | import java.util.concurrent.ConcurrentMap;
12 |
13 | /**
14 | * Utils method for ssl socket factory
15 | *
16 | * @author Liu Dong
17 | */
18 | public class SSLSocketFactories {
19 |
20 | // To reuse the connection, settings on the underlying socket must use the exact same objects.
21 |
22 | private static final SSLSocketFactory sslSocketFactoryLazy = _getTrustAllSSLSocketFactory();
23 |
24 | public static SSLSocketFactory _getTrustAllSSLSocketFactory() {
25 | TrustManager trustManager = new TrustAllTrustManager();
26 | SSLContext sslContext;
27 | try {
28 | sslContext = SSLContext.getInstance("SSL");
29 | sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
30 | } catch (NoSuchAlgorithmException | KeyManagementException e) {
31 | throw new RequestsException(e);
32 | }
33 |
34 | return sslContext.getSocketFactory();
35 | }
36 |
37 |
38 | public static SSLSocketFactory getTrustAllSSLSocketFactory() {
39 | return sslSocketFactoryLazy;
40 | }
41 |
42 | private static final ConcurrentMap map = new ConcurrentHashMap<>();
43 |
44 | private static SSLSocketFactory _getCustomSSLSocketFactory(KeyStore keyStore) {
45 | TrustManager trustManager = new CustomCertTrustManager(keyStore);
46 | SSLContext sslContext;
47 | try {
48 | sslContext = SSLContext.getInstance("SSL");
49 | sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
50 | } catch (NoSuchAlgorithmException | KeyManagementException e) {
51 | throw new RequestsException(e);
52 | }
53 |
54 | return sslContext.getSocketFactory();
55 | }
56 |
57 | public static SSLSocketFactory getCustomTrustSSLSocketFactory(KeyStore keyStore) {
58 | if (!map.containsKey(keyStore)) {
59 | map.put(keyStore, _getCustomSSLSocketFactory(keyStore));
60 | }
61 | return map.get(keyStore);
62 | }
63 |
64 | static class TrustAllTrustManager implements X509TrustManager {
65 | @Override
66 | public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
67 | }
68 |
69 | @Override
70 | public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
71 | }
72 |
73 | @Override
74 | public X509Certificate[] getAcceptedIssuers() {
75 | return null;
76 | }
77 | }
78 |
79 | /**
80 | * Trust Manager that trust additional x509 certificates provided by user
81 | */
82 | static class CustomCertTrustManager implements X509TrustManager {
83 |
84 | private final KeyStore keyStore;
85 | private final X509TrustManager defaultTrustManager;
86 | private final X509TrustManager trustManager;
87 |
88 | public CustomCertTrustManager(KeyStore keyStore) {
89 | this.keyStore = keyStore;
90 | // get the default trust manager
91 | TrustManagerFactory defaultTrustManagerFactory;
92 | try {
93 | defaultTrustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
94 | defaultTrustManagerFactory.init((KeyStore) null);
95 | } catch (NoSuchAlgorithmException | KeyStoreException e) {
96 | throw new TrustManagerLoadFailedException(e);
97 | }
98 | X509TrustManager defaultTrustManager = null;
99 | for (TrustManager tm : defaultTrustManagerFactory.getTrustManagers()) {
100 | if (tm instanceof X509TrustManager) {
101 | defaultTrustManager = (X509TrustManager) tm;
102 | break;
103 | }
104 | }
105 | if (defaultTrustManager == null) {
106 | throw new TrustManagerLoadFailedException("Default X509TrustManager not found");
107 | }
108 | this.defaultTrustManager = defaultTrustManager;
109 |
110 | TrustManagerFactory trustManagerFactory;
111 | try {
112 | trustManagerFactory = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
113 | trustManagerFactory.init(keyStore);
114 | } catch (NoSuchAlgorithmException | NoSuchProviderException | KeyStoreException e) {
115 | throw new TrustManagerLoadFailedException(e);
116 | }
117 |
118 | X509TrustManager trustManager = null;
119 | for (TrustManager tm : trustManagerFactory.getTrustManagers()) {
120 | if (tm instanceof X509TrustManager) {
121 | trustManager = (X509TrustManager) tm;
122 | break;
123 | }
124 | }
125 | if (trustManager == null) {
126 | throw new TrustManagerLoadFailedException("X509TrustManager for user keystore not found");
127 | }
128 | this.trustManager = trustManager;
129 | }
130 |
131 | @Override
132 | public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
133 | try {
134 | trustManager.checkClientTrusted(chain, authType);
135 | } catch (CertificateException e) {
136 | defaultTrustManager.checkClientTrusted(chain, authType);
137 | }
138 | }
139 |
140 | @Override
141 | public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
142 | try {
143 | trustManager.checkServerTrusted(chain, authType);
144 | } catch (CertificateException e) {
145 | defaultTrustManager.checkServerTrusted(chain, authType);
146 | }
147 | }
148 |
149 | @Override
150 | public X509Certificate[] getAcceptedIssuers() {
151 | X509Certificate[] defaultAcceptedIssuers = defaultTrustManager.getAcceptedIssuers();
152 | X509Certificate[] acceptedIssuers = trustManager.getAcceptedIssuers();
153 | X509Certificate[] result = new X509Certificate[defaultAcceptedIssuers.length + acceptedIssuers.length];
154 | System.arraycopy(defaultAcceptedIssuers, 0, result, 0, defaultAcceptedIssuers.length);
155 | System.arraycopy(acceptedIssuers, 0, result, defaultAcceptedIssuers.length, acceptedIssuers.length);
156 | return result;
157 | }
158 | }
159 |
160 | }
161 |
--------------------------------------------------------------------------------
/src/main/java/me/gv7/woodpecker/requests/utils/URLUtils.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.utils;
2 |
3 | import me.gv7.woodpecker.requests.Parameter;
4 | import me.gv7.woodpecker.requests.exception.RequestsException;
5 |
6 | import java.io.UnsupportedEncodingException;
7 | import java.net.MalformedURLException;
8 | import java.net.URL;
9 | import java.net.URLDecoder;
10 | import java.net.URLEncoder;
11 | import java.nio.charset.Charset;
12 | import java.util.ArrayList;
13 | import java.util.Collection;
14 | import java.util.List;
15 | import java.util.Map;
16 |
17 | /**
18 | * Util methods for encode / decode uri.
19 | */
20 | public class URLUtils {
21 |
22 | /**
23 | * Encode key-value form parameter
24 | */
25 | public static String encodeForm(Parameter query, Charset charset) {
26 | try {
27 | return URLEncoder.encode(query.name(), charset.name()) + "=" + URLEncoder.encode(query.value(),
28 | charset.name());
29 | } catch (UnsupportedEncodingException e) {
30 | // should not happen
31 | throw new RequestsException(e);
32 | }
33 | }
34 |
35 | /**
36 | * Encode multi form parameters
37 | */
38 | public static String encodeForms(Collection extends Parameter> queries, Charset charset) {
39 | StringBuilder sb = new StringBuilder();
40 | try {
41 | for (Parameter query : queries) {
42 | sb.append(URLEncoder.encode(query.name(), charset.name()));
43 | sb.append('=');
44 | sb.append(URLEncoder.encode(query.value(), charset.name()));
45 | sb.append('&');
46 | }
47 | } catch (UnsupportedEncodingException e) {
48 | // should not happen
49 | throw new RequestsException(e);
50 | }
51 | if (sb.length() > 0) {
52 | sb.deleteCharAt(sb.length() - 1);
53 | }
54 | return sb.toString();
55 | }
56 |
57 | /**
58 | * Decode key-value query parameter
59 | */
60 | public static Parameter decodeForm(String s, Charset charset) {
61 | int idx = s.indexOf("=");
62 | try {
63 | if (idx < 0) {
64 | return Parameter.of("", URLDecoder.decode(s, charset.name()));
65 | }
66 | return Parameter.of(URLDecoder.decode(s.substring(0, idx), charset.name()),
67 | URLDecoder.decode(s.substring(idx + 1), charset.name()));
68 | } catch (UnsupportedEncodingException e) {
69 | // should not happen
70 | throw new RequestsException(e);
71 | }
72 | }
73 |
74 | /**
75 | * Parse query params
76 | */
77 | public static List> decodeForms(String queryStr, Charset charset) {
78 | String[] queries = queryStr.split("&");
79 | List> list = new ArrayList<>(queries.length);
80 | for (String query : queries) {
81 | list.add(decodeForm(query, charset));
82 | }
83 |
84 | return list;
85 | }
86 |
87 | public static List> toStringParameters(Collection extends Map.Entry> params) {
88 | List> parameters = new ArrayList<>(params.size());
89 | for (Map.Entry entry : params) {
90 | parameters.add(Parameter.of(entry.getKey(), String.valueOf(entry.getValue())));
91 | }
92 | return parameters;
93 | }
94 |
95 | public static URL joinUrl(URL url, Collection extends Parameter> params, Charset charset) {
96 | if (params.isEmpty()) {
97 | return url;
98 | }
99 |
100 | StringBuilder sb = new StringBuilder();
101 | sb.append(url.getProtocol()).append(':');
102 | if (url.getAuthority() != null && !url.getAuthority().isEmpty()) {
103 | sb.append("//").append(url.getAuthority());
104 | }
105 | if (url.getPath() != null) {
106 | sb.append(url.getPath());
107 | }
108 |
109 | String query = url.getQuery();
110 | String newQuery = encodeForms(params, charset);
111 | if (query == null || query.isEmpty()) {
112 | sb.append('?').append(newQuery);
113 | } else {
114 | sb.append('?').append(query).append('&').append(newQuery);
115 | }
116 |
117 | if (url.getRef() != null) {
118 | sb.append('#').append(url.getRef());
119 | }
120 |
121 | URL fullURL;
122 | try {
123 | fullURL = new URL(sb.toString());
124 | } catch (MalformedURLException e) {
125 | throw new RequestsException(e);
126 |
127 | }
128 | return fullURL;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/main/java/me/gv7/woodpecker/requests/utils/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Utils classes, Only for internal use!
3 | *
4 | * @author Liu Dong
5 | */
6 | package me.gv7.woodpecker.requests.utils;
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/ChunkedHeaderTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests;
2 |
3 | import org.junit.Test;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | /**
9 | * @author c0ny1
10 | * @date 2023/04/11 16:32:50
11 | **/
12 | public class ChunkedHeaderTest {
13 | /**
14 | * 问题:无法发送Request header Transfer-Encoding: chunked
15 | * 原因:经过测试会在分块传输头会在sun.net.www.protocol.http.HttpURLConnection#writeRequests()处被删除。
16 | * 注意:
17 | * 1.不要用burp抓包测试,burp似乎对分块进行合并,请使用wireshark。
18 | * 2.在me.gv7.woodpecker.requests.executor.URLConnectionExecutor#doRequest(me.gv7.woodpecker.requests.Request)处
19 | * 加入conn.setChunkedStreamingMode(1);可以发送Transfer-Encoding: chunked,但是没发完全控制body。要支持分块传输还需要深入深入研究。
20 | *
21 | */
22 | @Test
23 | public void sendChunkedHeader(){
24 | Map header = new HashMap();
25 | header.put("Transfer-Encoding","chunked");
26 | header.put("aaa","bbb");
27 | Requests.post("http://127.0.0.1:1664/").headers(header).body("2\r\nxxs3\r\ndwe").proxy(Proxies.httpProxy("127.0.0.1",1664)).send();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/CookieTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests;
2 |
3 | public class CookieTest {
4 |
5 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/HeadersTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests;
2 |
3 | import me.gv7.woodpecker.requests.config.HttpConfigManager;
4 | import net.dongliu.commons.collection.Lists;
5 | import org.junit.Test;
6 |
7 | import java.net.InetSocketAddress;
8 | import java.net.Proxy;
9 | import java.util.Arrays;
10 | import java.util.HashMap;
11 | import java.util.LinkedHashMap;
12 |
13 | import static org.junit.Assert.assertEquals;
14 |
15 | /**
16 | * @author Liu Dong
17 | */
18 | public class HeadersTest {
19 | @Test
20 | public void getHeaders() {
21 | Headers headers = new Headers(Arrays.asList(
22 | new Header("Location", "www"),
23 | new Header("Location", "www2"),
24 | new Header("Content-Length", "100")
25 | ));
26 | assertEquals(Lists.of("www", "www2"), headers.getHeaders("Location"));
27 | }
28 |
29 | @Test
30 | public void getHeader() {
31 | Headers headers = new Headers(Lists.of(
32 | new Header("Location", "www"),
33 | new Header("Location", "www2"),
34 | new Header("Content-Length", "100")
35 | ));
36 | assertEquals("www", headers.getHeader("Location"));
37 | assertEquals("www", headers.getHeader("location"));
38 | }
39 |
40 | @Test
41 | public void getLongHeader() {
42 | Headers headers = new Headers(Lists.of(
43 | new Header("Location", "www"),
44 | new Header("Location", "www2"),
45 | new Header("Content-Length", "100")
46 | ));
47 | assertEquals(100, headers.getLongHeader("Content-Length", -1));
48 | }
49 |
50 | /**
51 | * 测试不覆盖模式下,Host以及用户设置的头部是否保持原样
52 | */
53 | @Test
54 | public void setNoOverwriteHeader(){
55 | LinkedHashMap newHeaders = new LinkedHashMap<>();
56 | newHeaders.put("Host","overwrite.com");
57 | newHeaders.put("aaa","overwrite");
58 | newHeaders.put("bbb","bbb");
59 | HttpConfigManager.setCustomHttpHeaderConfig(newHeaders,false);
60 | LinkedHashMap headers = new LinkedHashMap<>();
61 | headers.put("aaa","aaa");
62 | headers.put("ccc","ccc");
63 | RequestBuilder requestBuilder = Requests.get("http://woodpecker.gv7.me/index").headers(headers);
64 | requestBuilder.build();
65 |
66 | assertEquals(null,requestBuilder.getHeader("Host"));
67 | assertEquals("aaa",requestBuilder.getHeader("aaa"));
68 | assertEquals("bbb",requestBuilder.getHeader("bbb"));
69 | assertEquals("ccc",requestBuilder.getHeader("ccc"));
70 | }
71 |
72 | /**
73 | * 测试覆盖模式下是否覆盖成功
74 | */
75 | @Test
76 | public void setOverwriteHeader(){
77 | LinkedHashMap newHeaders = new LinkedHashMap<>();
78 | newHeaders.put("Host","overwrite.com");
79 | newHeaders.put("aaa","overwrite");
80 | newHeaders.put("bbb","bbb");
81 | HttpConfigManager.setCustomHttpHeaderConfig(newHeaders,true);
82 | LinkedHashMap headers = new LinkedHashMap<>();
83 | headers.put("aaa","aaa");
84 | headers.put("ccc","ccc");
85 | RequestBuilder requestBuilder = Requests.get("http://woodpecker.gv7.me/index").headers(headers);
86 | requestBuilder.build();
87 |
88 | assertEquals("overwrite.com",requestBuilder.getHeader("Host"));
89 | assertEquals("overwrite",requestBuilder.getHeader("aaa"));
90 | assertEquals("bbb",requestBuilder.getHeader("bbb"));
91 | assertEquals("ccc",requestBuilder.getHeader("ccc")); // 测试是否用户未被覆盖的header否否保持
92 | }
93 |
94 | /**
95 | * 测试新增多个header是否会覆盖
96 | */
97 | @Test
98 | public void setManyHeader(){
99 | HashMap h = new HashMap<>();
100 | h.put("header1","header1");
101 | HashMap h2 = new HashMap();
102 | h2.put("header2","header2");
103 | HashMap h3 = new HashMap();
104 | h3.put("header3","header3");
105 | String url = "http://www.baidu.com";
106 | RequestBuilder requestBuilder = Requests.get(url)
107 | .headers(h) // header1
108 | .headers(h2) // header2
109 | .headers(h3.entrySet()) // header3
110 | .headers(Lists.of(new Header("header4","header4"))); // header4
111 | assertEquals("header1",requestBuilder.getHeader("header1"));
112 | assertEquals("header2",requestBuilder.getHeader("header2"));
113 | assertEquals("header3",requestBuilder.getHeader("header3"));
114 | assertEquals("header4",requestBuilder.getHeader("header4"));
115 | }
116 |
117 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/IgnoreHttpConfigTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests;
2 |
3 | import me.gv7.woodpecker.requests.config.HttpConfigManager;
4 | import org.junit.Test;
5 |
6 | import java.util.LinkedHashMap;
7 |
8 | import static org.junit.Assert.assertEquals;
9 |
10 | public class IgnoreHttpConfigTest {
11 | /**
12 | * 设置开启忽略Http配置模式
13 | */
14 | @Test
15 | public void ignoreHttpConfigTest(){
16 | LinkedHashMap newHeaders = new LinkedHashMap<>();
17 | newHeaders.put("aaa","overwrite");
18 | newHeaders.put("bbb","bbb");
19 | HttpConfigManager.setCustomHttpHeaderConfig(newHeaders,true);
20 |
21 | LinkedHashMap headers = new LinkedHashMap<>();
22 | headers.put("aaa","aaa");
23 | headers.put("ccc","ccc");
24 | RequestBuilder requestBuilder = Requests.get("http://woodpecker.gv7.me/index").headers(headers).ignoreHttpConfig(true);
25 | requestBuilder.build();
26 |
27 | assertEquals("aaa",requestBuilder.getHeader("aaa"));
28 | assertEquals(null,requestBuilder.getHeader("bbb"));
29 | assertEquals("ccc",requestBuilder.getHeader("ccc")); // 测试是否用户未被覆盖的header否否保持
30 | }
31 |
32 | /**
33 | * 设置关闭忽略Http配置模式
34 | */
35 | @Test
36 | public void notIgnoreHttpConfigTest(){
37 | LinkedHashMap newHeaders = new LinkedHashMap<>();
38 | newHeaders.put("aaa","overwrite");
39 | newHeaders.put("bbb","bbb");
40 | HttpConfigManager.setCustomHttpHeaderConfig(newHeaders,true);
41 |
42 | LinkedHashMap headers = new LinkedHashMap<>();
43 | headers.put("aaa","aaa");
44 | headers.put("ccc","ccc");
45 | RequestBuilder requestBuilder = Requests.get("http://woodpecker.gv7.me/index").headers(headers).ignoreHttpConfig(false);
46 | requestBuilder.build();
47 |
48 | assertEquals("overwrite",requestBuilder.getHeader("aaa"));
49 | assertEquals("bbb",requestBuilder.getHeader("bbb"));
50 | assertEquals("ccc",requestBuilder.getHeader("ccc")); // 测试是否用户未被覆盖的header否否保持
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/MultiPartTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests;
2 |
3 | import me.gv7.woodpecker.requests.body.Part;
4 | import org.junit.Test;
5 |
6 | import java.io.File;
7 |
8 | public class MultiPartTest {
9 |
10 | @Test
11 | public void testOf() throws Exception {
12 | Part multiPart = Part.file("writeTo", new File("MultiPartTest.java"));
13 | }
14 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/RequestsProxyTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests;
2 |
3 | import me.gv7.woodpecker.requests.config.HttpConfigManager;
4 | import me.gv7.woodpecker.requests.mock.MockServer;
5 | import org.junit.AfterClass;
6 | import org.junit.BeforeClass;
7 | import org.junit.Ignore;
8 | import org.junit.Test;
9 |
10 | import java.net.Proxy;
11 |
12 | import static org.junit.Assert.assertEquals;
13 |
14 | /**
15 | * @author Liu Dong
16 | */
17 | @Ignore
18 | public class RequestsProxyTest {
19 |
20 | private static MockServer server = new MockServer();
21 |
22 | @BeforeClass
23 | public static void init() {
24 | server.start();
25 | }
26 |
27 | @AfterClass
28 | public static void destroy() {
29 | server.stop();
30 | }
31 |
32 | @Test
33 | public void testHttpProxy() {
34 | // http proxy with redirect
35 | RawResponse response = Requests
36 | .get("https://www.google.com")
37 | .proxy(Proxies.httpProxy("127.0.0.1", 1081))
38 | .send();
39 | response.close();
40 | assertEquals(200, response.statusCode());
41 | }
42 |
43 | @Test
44 | public void testSocksProxy() {
45 | // socks proxy with redirect
46 | RawResponse response = Requests
47 | .get("https://www.google.com")
48 | .proxy(Proxies.socksProxy("127.0.0.1", 1080))
49 | .send();
50 | response.close();
51 | assertEquals(200, response.statusCode());
52 | }
53 |
54 | @Test
55 | public void testHttpProxy1() throws Exception {
56 | HttpConfigManager.setProxyConfig(true
57 | ,"http"
58 | ,"127.0.0.1"
59 | ,8080
60 | ,null
61 | ,null);
62 | RawResponse response = Requests.method("GET","http://wwww.baidu.com/xxx").proxy(Proxy.NO_PROXY).send();
63 | System.out.println(response.readToText());
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/RequestsTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests;
2 |
3 | import net.dongliu.commons.collection.Lists;
4 | import me.gv7.woodpecker.requests.body.InputStreamSupplier;
5 | import me.gv7.woodpecker.requests.body.Part;
6 | import me.gv7.woodpecker.requests.json.TypeInfer;
7 | import me.gv7.woodpecker.requests.mock.MockServer;
8 | import org.junit.AfterClass;
9 | import org.junit.BeforeClass;
10 | import org.junit.Test;
11 |
12 | import java.io.InputStream;
13 | import java.nio.charset.StandardCharsets;
14 | import java.security.KeyStore;
15 | import java.util.HashMap;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | import static org.junit.Assert.*;
20 |
21 | public class RequestsTest {
22 |
23 | private static MockServer server = new MockServer();
24 |
25 | @BeforeClass
26 | public static void init() {
27 | server.start();
28 | }
29 |
30 | @AfterClass
31 | public static void destroy() {
32 | server.stop();
33 | }
34 |
35 | @Test
36 | public void testGet() {
37 | String resp = Requests.get("http://127.0.0.1:8080")
38 | .requestCharset(StandardCharsets.UTF_8).send().readToText();
39 | assertFalse(resp.isEmpty());
40 |
41 | resp = Requests.get("http://127.0.0.1:8080").send().readToText();
42 | assertFalse(resp.isEmpty());
43 |
44 | // get with params
45 | Map map = new HashMap<>();
46 | map.put("wd", "test");
47 | resp = Requests.get("http://127.0.0.1:8080").params(map).send().readToText();
48 | assertFalse(resp.isEmpty());
49 | assertTrue(resp.contains("wd=test"));
50 | }
51 |
52 | @Test
53 | public void testHead() {
54 | RawResponse resp = Requests.head("http://127.0.0.1:8080")
55 | .requestCharset(StandardCharsets.UTF_8).send();
56 | assertEquals(200, resp.statusCode());
57 | String statusLine = resp.statusLine();
58 | assertEquals("HTTP/1.1 200 OK", statusLine);
59 | String text = resp.readToText();
60 | assertTrue(text.isEmpty());
61 | }
62 |
63 | @Test
64 | public void testPost() {
65 | // form encoded post
66 | String text = Requests.post("http://127.0.0.1:8080/post")
67 | .body(Parameter.of("wd", "test"))
68 | .send().readToText();
69 | assertTrue(text.contains("wd=test"));
70 | }
71 |
72 | @Test
73 | public void testCookie() {
74 | Response response = Requests.get("http://127.0.0.1:8080/cookie")
75 | .cookies(Parameter.of("test", "value")).send().toTextResponse();
76 | boolean flag = false;
77 | for (Cookie cookie : response.cookies()) {
78 | if (cookie.name().equals("test")) {
79 | flag = true;
80 | break;
81 | }
82 | }
83 | assertTrue(flag);
84 | }
85 |
86 | @Test
87 | public void testBasicAuth() {
88 | Response response = Requests.get("http://127.0.0.1:8080/basicAuth")
89 | .basicAuth("test", "password")
90 | .send().toTextResponse();
91 | assertEquals(200, response.statusCode());
92 | }
93 |
94 | @Test
95 | public void testRedirect() {
96 | Response resp = Requests.get("http://127.0.0.1:8080/redirect").userAgent("my-user-agent")
97 | .send().toTextResponse();
98 | assertEquals(200, resp.statusCode());
99 | assertTrue(resp.body().contains("/redirected"));
100 | assertTrue(resp.body().contains("my-user-agent"));
101 | }
102 |
103 | @Test
104 | public void testMultiPart() {
105 | String body = Requests.post("http://127.0.0.1:8080/multi_part")
106 | .multiPartBody(Part.file("writeTo", "keystore", new InputStreamSupplier() {
107 | @Override
108 | public InputStream get() {
109 | return this.getClass().getResourceAsStream("/keystore");
110 | }
111 | }).contentType("application/octem-stream"))
112 | .send().readToText();
113 | assertTrue(body.contains("writeTo"));
114 | assertTrue(body.contains("application/octem-stream"));
115 | }
116 |
117 |
118 | @Test
119 | public void testMultiPartText() {
120 | String body = Requests.post("http://127.0.0.1:8080/multi_part")
121 | .multiPartBody(Part.text("test", "this is test value"))
122 | .send().readToText();
123 | assertTrue(body.contains("this is test value"));
124 | assertTrue(!body.contains("plain/text"));
125 | }
126 |
127 | @Test
128 | public void sendJson() {
129 | String text = Requests.post("http://127.0.0.1:8080/echo_body").jsonBody(Lists.of(1, 2, 3))
130 | .send().readToText();
131 | assertTrue(text.startsWith("["));
132 | assertTrue(text.endsWith("]"));
133 | }
134 |
135 | @Test
136 | public void receiveJson() {
137 | List list = Requests.post("http://127.0.0.1:8080/echo_body").jsonBody(Lists.of(1, 2, 3))
138 | .send().readToJson(new TypeInfer>() {
139 | });
140 | assertEquals(3, list.size());
141 | }
142 |
143 | @Test
144 | public void sendHeaders() {
145 | RequestBuilder.DEBUG = true;
146 | String text = Requests.get("http://gv7.me/echo_header")
147 | .headers(new Header("Host", "www.test.com"), new Header("TestHeader", 1))
148 | .proxy(Proxies.httpProxy("127.0.0.1",8080))
149 | .send().readToText();
150 | assertTrue(text.contains("Host: www.test.com"));
151 | assertTrue(text.contains("TestHeader: 1"));
152 | }
153 |
154 | @Test
155 | public void sendHeaders2() {
156 | RequestBuilder.DEBUG = true;
157 | Map headers = new HashMap();
158 | headers.put("TestHeader","1");
159 | String text = Requests.get("http://gv7.me/echo_header")
160 | .headers(headers)
161 | .proxy(Proxies.httpProxy("127.0.0.1",8080))
162 | .send().readToText();
163 | assertTrue(text.contains("Host: www.test.com"));
164 | assertTrue(text.contains("TestHeader: 1"));
165 | }
166 |
167 | @Test
168 | public void testHttps() {
169 | Response response = Requests.get("https://127.0.0.1:8443/https")
170 | .verify(false).send().toTextResponse();
171 | assertEquals(200, response.statusCode());
172 |
173 |
174 | KeyStore keyStore = KeyStores.load(this.getClass().getResourceAsStream("/keystore"), "123456".toCharArray());
175 | response = Requests.get("https://127.0.0.1:8443/https")
176 | .keyStore(keyStore)
177 | .send().toTextResponse();
178 | assertEquals(200, response.statusCode());
179 | }
180 |
181 | @Test
182 | public void testInterceptor() {
183 | final long[] statusCode = {0};
184 | Interceptor interceptor = (target, request) -> {
185 | RawResponse response = target.proceed(request);
186 | statusCode[0] = response.statusCode();
187 | return response;
188 | };
189 |
190 | String text = Requests.get("http://127.0.0.1:8080/echo_header")
191 | .interceptors(interceptor)
192 | .send().readToText();
193 | assertFalse(text.isEmpty());
194 | assertTrue(statusCode[0] > 0);
195 | }
196 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/SessionTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests;
2 |
3 | import me.gv7.woodpecker.requests.mock.MockServer;
4 | import org.junit.AfterClass;
5 | import org.junit.BeforeClass;
6 | import org.junit.Test;
7 |
8 | import static org.junit.Assert.assertEquals;
9 | import static org.junit.Assert.assertTrue;
10 |
11 | public class SessionTest {
12 |
13 | private static MockServer server = new MockServer();
14 |
15 | @BeforeClass
16 | public static void init() {
17 | server.start();
18 | }
19 |
20 | @AfterClass
21 | public static void destroy() {
22 | server.stop();
23 | }
24 |
25 | @Test
26 | public void testSession() {
27 | Session session = Requests.session();
28 | String response = session.get("http://127.0.0.1:8080").send().readToText();
29 | assertTrue(!response.isEmpty());
30 | }
31 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/body/RequestBodyTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.body;
2 |
3 | import net.dongliu.commons.collection.Lists;
4 | import org.junit.Test;
5 |
6 | import java.io.ByteArrayOutputStream;
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.List;
9 |
10 | import static org.junit.Assert.assertEquals;
11 |
12 | public class RequestBodyTest {
13 | @Test
14 | public void json() throws Exception {
15 | RequestBody> body = RequestBody.json(Lists.of("1", "2", "3"));
16 | assertEquals("application/json", body.contentType());
17 |
18 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
19 | body.writeBody(bos, StandardCharsets.UTF_8);
20 | String str = bos.toString("UTF-8");
21 | assertEquals("[\"1\",\"2\",\"3\"]", str);
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/executor/DefaultCookieJarTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.executor;
2 |
3 | import net.dongliu.commons.collection.Lists;
4 | import net.dongliu.commons.collection.Sets;
5 | import me.gv7.woodpecker.requests.Cookie;
6 | import org.junit.Test;
7 |
8 | import java.net.URL;
9 | import java.util.HashSet;
10 | import java.util.List;
11 | import java.util.concurrent.TimeUnit;
12 |
13 | import static org.junit.Assert.assertEquals;
14 |
15 | public class DefaultCookieJarTest {
16 | @Test
17 | public void storeCookies() {
18 | long now = System.currentTimeMillis();
19 | long oneHour = TimeUnit.HOURS.toMillis(1);
20 | CookieJar cookieJar = new DefaultCookieJar();
21 | List cookies = Lists.of(
22 | new Cookie("test.com", "/", "test", "value", 0, false, false),
23 | new Cookie("test.com", "/test/", "test", "value1", 0, false, false),
24 | new Cookie("test.com", "/test/", "test1", "value1", 0, false, false),
25 | new Cookie("test1.com", "/", "test2", "value2", 0, false, false)
26 | );
27 | cookieJar.storeCookies(cookies);
28 | assertEquals(new HashSet<>(cookies), new HashSet<>(cookieJar.getCookies()));
29 |
30 | List cookies1 = Lists.of(
31 | new Cookie("test.com", "/test/", "test1", "value1", now - oneHour, false, false),
32 | new Cookie("test1.com", "/", "test2", "value2", now + oneHour, false, false)
33 | );
34 | cookieJar.storeCookies(cookies1);
35 | assertEquals(Sets.of(
36 | new Cookie("test.com", "/", "test", "value", 0, false, false),
37 | new Cookie("test.com", "/test/", "test", "value1", 0, false, false),
38 | new Cookie("test1.com", "/", "test2", "value2", now + oneHour, false, false)
39 | ), new HashSet<>(cookieJar.getCookies()));
40 | }
41 |
42 | @Test
43 | public void getCookies() throws Exception {
44 | CookieJar cookieJar = new DefaultCookieJar();
45 | List cookies = Lists.of(
46 | new Cookie("test.com", "/", "test", "value", 0, false, false),
47 | new Cookie("test.com", "/test/", "test", "value1", 0, false, false),
48 | new Cookie("test.com", "/test/", "test1", "value1", 0, false, false),
49 | new Cookie("test1.com", "/", "test2", "value2", 0, false, false)
50 | );
51 | cookieJar.storeCookies(cookies);
52 |
53 | URL url = new URL("http://www.test.com/test/");
54 | List matched = cookieJar.getCookies(url);
55 | assertEquals(3, matched.size());
56 | assertEquals(Sets.of(
57 | new Cookie("test.com", "/test/", "test", "value1", 0, false, false),
58 | new Cookie("test.com", "/test/", "test1", "value1", 0, false, false)
59 | ), new HashSet<>(matched.subList(0, 2)));
60 | assertEquals(new Cookie("test.com", "/", "test", "value", 0, false, false), matched.get(2));
61 | }
62 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/json/FastJsonProcessorTest.java:
--------------------------------------------------------------------------------
1 | //package me.gv7.woodpecker.requests.json;
2 | //
3 | //import org.junit.Test;
4 | //
5 | //import java.io.ByteArrayInputStream;
6 | //import java.io.StringWriter;
7 | //import java.nio.charset.StandardCharsets;
8 | //
9 | //import static org.junit.Assert.assertEquals;
10 | //
11 | ///**
12 | // * @author Liu Dong
13 | // */
14 | //public class FastJsonProcessorTest {
15 | // @Test
16 | // public void marshal() throws Exception {
17 | // FastJsonProcessor jsonProvider = new FastJsonProcessor();
18 | // try (StringWriter writer = new StringWriter()) {
19 | // jsonProvider.marshal(writer, "test");
20 | // String s = writer.toString();
21 | // assertEquals("\"test\"", s);
22 | // }
23 | // }
24 | //
25 | // @Test
26 | // public void unmarshal() throws Exception {
27 | // FastJsonProcessor jsonProvider = new FastJsonProcessor();
28 | // String str = jsonProvider.unmarshal(new ByteArrayInputStream("\"test\"".getBytes()), StandardCharsets.UTF_8,
29 | // String.class);
30 | // assertEquals("test", str);
31 | // }
32 | //
33 | //}
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/json/JsonLookupTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.json;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * @author Liu Dong
9 | */
10 | public class JsonLookupTest {
11 |
12 | @Test
13 | public void test() {
14 | JsonLookup lookup = JsonLookup.getInstance();
15 | assertTrue(lookup.hasFastJson());
16 | assertTrue(lookup.hasGson());
17 | assertTrue(lookup.hasJackson());
18 | }
19 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/mock/EchoBodyServlet.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.mock;
2 |
3 |
4 | import net.dongliu.commons.io.Readers;
5 |
6 | import javax.servlet.ServletException;
7 | import javax.servlet.http.HttpServlet;
8 | import javax.servlet.http.HttpServletRequest;
9 | import javax.servlet.http.HttpServletResponse;
10 | import java.io.IOException;
11 | import java.io.PrintWriter;
12 |
13 | /**
14 | * @author Liu Dong {@literal }
15 | */
16 | public class EchoBodyServlet extends HttpServlet {
17 |
18 | @Override
19 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
20 | throws ServletException, IOException {
21 | String body = Readers.readAll(request.getReader());
22 |
23 | response.setContentType("text/plain");
24 | response.setCharacterEncoding(request.getCharacterEncoding());
25 | PrintWriter out = response.getWriter();
26 | out.write(body);
27 | out.flush();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/mock/EchoHeaderServlet.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.mock;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.http.HttpServlet;
5 | import javax.servlet.http.HttpServletRequest;
6 | import javax.servlet.http.HttpServletResponse;
7 | import java.io.IOException;
8 | import java.io.PrintWriter;
9 | import java.util.Enumeration;
10 |
11 | /**
12 | * @author Liu Dong {@literal }
13 | */
14 | public class EchoHeaderServlet extends HttpServlet {
15 |
16 | @Override
17 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
18 | throws ServletException, IOException {
19 | StringBuilder sb = new StringBuilder();
20 | Enumeration headerNames = request.getHeaderNames();
21 | while (headerNames.hasMoreElements()) {
22 | String headerName = headerNames.nextElement();
23 | String header = request.getHeader(headerName);
24 | sb.append(headerName).append(": ").append(header).append("\n");
25 | }
26 | String headers = sb.toString();
27 |
28 | response.setContentType("text/plain");
29 | response.setCharacterEncoding("UTF-8");
30 | PrintWriter out = response.getWriter();
31 | out.write(headers);
32 | out.flush();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/mock/MockBasicAuthenticationServlet.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.mock;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.http.HttpServlet;
5 | import javax.servlet.http.HttpServletRequest;
6 | import javax.servlet.http.HttpServletResponse;
7 | import java.io.IOException;
8 | import java.io.PrintWriter;
9 | import java.util.Base64;
10 |
11 | /**
12 | * @author Liu Dong {@literal }
13 | */
14 | public class MockBasicAuthenticationServlet extends HttpServlet {
15 |
16 | private static final long serialVersionUID = 1567638593606667604L;
17 |
18 | public void doGet(HttpServletRequest req, HttpServletResponse res)
19 | throws ServletException, IOException {
20 |
21 | PrintWriter out = res.getWriter();
22 | String auth = req.getHeader("Authorization");
23 | if (!allowUser(auth)) {
24 | // Not allowed, so report he's unauthorized
25 | res.setHeader("WWW-Authenticate", "BASIC realm=\"test basic auth\"");
26 | res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
27 | // Could offer to add him to the allowed user list
28 | } else {
29 | // Allowed, so show him the secret stuff
30 | out.println(req.getRequestURI());
31 | }
32 | }
33 |
34 | private boolean allowUser(String auth) {
35 |
36 | if (auth == null) {
37 | return false;
38 | }
39 | if (!auth.toUpperCase().startsWith("BASIC ")) {
40 | return false;
41 | }
42 | String encodedToken = auth.substring(6);
43 | String token = new String(Base64.getDecoder().decode(encodedToken));
44 |
45 | return "test:password".equals(token);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/mock/MockGetServlet.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.mock;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.http.Cookie;
5 | import javax.servlet.http.HttpServlet;
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 | import java.io.IOException;
9 | import java.io.PrintWriter;
10 | import java.util.Enumeration;
11 |
12 | /**
13 | * @author Liu Dong {@literal }
14 | */
15 | public class MockGetServlet extends HttpServlet {
16 |
17 | @Override
18 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
19 | throws ServletException, IOException {
20 | String uri = request.getRequestURI();
21 | String queryStr = request.getQueryString();
22 |
23 | StringBuilder sb = new StringBuilder();
24 | Enumeration headerNames = request.getHeaderNames();
25 | while (headerNames.hasMoreElements()) {
26 | String headerName = headerNames.nextElement();
27 | sb.append(headerName).append('=');
28 | Enumeration headerValues = request.getHeaders(headerName);
29 | while (headerValues.hasMoreElements()) {
30 | String headerValue = headerValues.nextElement();
31 | sb.append(headerValue).append(';');
32 | }
33 | sb.deleteCharAt(sb.length() - 1);
34 | sb.append('\n');
35 | }
36 | sb.deleteCharAt(sb.length() - 1);
37 | String headers = sb.toString();
38 |
39 | response.setContentType("text/plain");
40 | response.setCharacterEncoding("UTF-8");
41 | // cookie
42 | Cookie[] cookies = request.getCookies();
43 | if (cookies != null) {
44 | for (Cookie cookie : cookies) {
45 | response.addCookie(cookie);
46 | }
47 | }
48 |
49 | PrintWriter out = response.getWriter();
50 |
51 | switch (uri) {
52 | case "/redirect":
53 | response.sendRedirect("/redirected");
54 | break;
55 | default:
56 | out.println(uri);
57 | out.println(queryStr);
58 | out.println(sb.toString());
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/mock/MockMultiPartServlet.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.mock;
2 |
3 | import net.dongliu.commons.io.InputStreams;
4 | import org.eclipse.jetty.server.Request;
5 |
6 | import javax.servlet.MultipartConfigElement;
7 | import javax.servlet.ServletException;
8 | import javax.servlet.http.HttpServlet;
9 | import javax.servlet.http.HttpServletRequest;
10 | import javax.servlet.http.HttpServletResponse;
11 | import javax.servlet.http.Part;
12 | import java.io.IOException;
13 | import java.io.InputStream;
14 | import java.io.OutputStream;
15 | import java.nio.charset.StandardCharsets;
16 | import java.util.Collection;
17 |
18 | /**
19 | * @author Liu Dong {@literal }
20 | */
21 | public class MockMultiPartServlet extends HttpServlet {
22 |
23 | private static final MultipartConfigElement MULTI_PART_CONFIG = new MultipartConfigElement(System.getProperty
24 | ("java.io.tmpdir"));
25 |
26 | @Override
27 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
28 | throws ServletException, IOException {
29 | request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG);
30 |
31 | Collection parts = request.getParts();
32 |
33 | response.setContentType("text/plain");
34 | response.setCharacterEncoding("UTF-8");
35 | response.setStatus(HttpServletResponse.SC_OK);
36 | OutputStream out = response.getOutputStream();
37 | for (Part part : parts) {
38 | out.write(part.getName().getBytes(StandardCharsets.UTF_8));
39 | out.write('\n');
40 | if (part.getContentType() != null) {
41 | out.write(part.getContentType().getBytes(StandardCharsets.UTF_8));
42 | out.write('\n');
43 | }
44 | try (InputStream in = part.getInputStream()) {
45 | InputStreams.transferTo(in, out);
46 | }
47 | out.write('\n');
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/mock/MockPostServlet.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.mock;
2 |
3 | import javax.servlet.ServletException;
4 | import javax.servlet.http.HttpServlet;
5 | import javax.servlet.http.HttpServletRequest;
6 | import javax.servlet.http.HttpServletResponse;
7 | import java.io.IOException;
8 | import java.io.PrintWriter;
9 | import java.util.Map;
10 |
11 | /**
12 | * @author Liu Dong {@literal }
13 | */
14 | public class MockPostServlet extends HttpServlet {
15 |
16 | @Override
17 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
18 | throws ServletException, IOException {
19 | String uri = request.getRequestURI();
20 | Map params = request.getParameterMap();
21 |
22 | response.setContentType("text/plain");
23 | response.setCharacterEncoding("UTF-8");
24 | response.setStatus(HttpServletResponse.SC_OK);
25 | PrintWriter out = response.getWriter();
26 | out.println(uri);
27 | for (Map.Entry entry : params.entrySet()) {
28 | out.println(entry.getKey() + "=" + entry.getValue()[0]);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/mock/MockServer.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.mock;
2 |
3 | import org.eclipse.jetty.http.HttpVersion;
4 | import org.eclipse.jetty.server.*;
5 | import org.eclipse.jetty.servlet.ServletHandler;
6 | import org.eclipse.jetty.util.ssl.SslContextFactory;
7 |
8 | /**
9 | * @author Liu Dong {@literal }
10 | */
11 | public class MockServer {
12 |
13 | private Server server;
14 |
15 | public void start() {
16 | server = new Server();
17 |
18 | HttpConfiguration http_config = new HttpConfiguration();
19 | http_config.setSecureScheme("https");
20 | http_config.setSecurePort(8443);
21 | http_config.setOutputBufferSize(32768);
22 |
23 | ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(http_config));
24 | http.setPort(8080);
25 | http.setIdleTimeout(30000);
26 |
27 | SslContextFactory sslContextFactory = new SslContextFactory();
28 | sslContextFactory.setKeyStorePath(this.getClass().getResource("/keystore").toExternalForm());
29 | sslContextFactory.setKeyStorePassword("123456");
30 | sslContextFactory.setKeyManagerPassword("123456");
31 |
32 | HttpConfiguration httpsConfig = new HttpConfiguration(http_config);
33 | httpsConfig.addCustomizer(new SecureRequestCustomizer());
34 |
35 | ServerConnector https = new ServerConnector(server,
36 | new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
37 | new HttpConnectionFactory(httpsConfig));
38 | https.setPort(8443);
39 | https.setIdleTimeout(500000);
40 |
41 | server.setConnectors(new Connector[]{http, https});
42 |
43 | ServletHandler handler = new ServletHandler();
44 | server.setHandler(handler);
45 | handler.addServletWithMapping(MockGetServlet.class, "/*");
46 | handler.addServletWithMapping(MockPostServlet.class, "/post");
47 | handler.addServletWithMapping(MockBasicAuthenticationServlet.class, "/basicAuth");
48 | handler.addServletWithMapping(MockMultiPartServlet.class, "/multi_part");
49 | handler.addServletWithMapping(EchoBodyServlet.class, "/echo_body");
50 | handler.addServletWithMapping(EchoHeaderServlet.class, "/echo_header");
51 |
52 | // Start things up!
53 | try {
54 | server.start();
55 | } catch (Exception e) {
56 | throw new RuntimeException(e);
57 | }
58 |
59 | }
60 |
61 | public void join() {
62 | try {
63 | server.join();
64 | } catch (InterruptedException ignore) {
65 | }
66 | }
67 |
68 | public void stop() {
69 | try {
70 | server.stop();
71 | } catch (Exception ignore) {
72 | }
73 | }
74 |
75 | public static void main(String[] args) {
76 | MockServer server = new MockServer();
77 | server.start();
78 | server.join();
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/util/CookiesTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.util;
2 |
3 | import me.gv7.woodpecker.requests.Cookie;
4 | import me.gv7.woodpecker.requests.utils.Cookies;
5 | import org.junit.Test;
6 |
7 | import static org.junit.Assert.*;
8 |
9 | /**
10 | * @author Liu Dong
11 | */
12 | public class CookiesTest {
13 | @Test
14 | public void isSubDomain() throws Exception {
15 | assertTrue(Cookies.isDomainSuffix("www.baidu.com", "baidu.com"));
16 | assertTrue(Cookies.isDomainSuffix("baidu.com", "baidu.com"));
17 | assertFalse(Cookies.isDomainSuffix("a.com", "baidu.com"));
18 | assertFalse(Cookies.isDomainSuffix("ww.a.com", "baidu.com"));
19 | }
20 |
21 | @Test
22 | public void effectivePath() {
23 | assertEquals("/test/", Cookies.calculatePath("/test/123"));
24 | assertEquals("/", Cookies.calculatePath("/"));
25 | assertEquals("/", Cookies.calculatePath(""));
26 | }
27 |
28 | @Test
29 | public void isIP() {
30 | assertTrue(Cookies.isIP("202.38.64.10"));
31 | assertTrue(Cookies.isIP("2001:0DB8:0000:0023:0008:0800:200C:417A"));
32 | assertTrue(Cookies.isIP("2001:DB8:0:23:8:800:200C:417A"));
33 | assertTrue(Cookies.isIP("FF01:0:0:0:0:0:0:1101"));
34 | assertTrue(Cookies.isIP("::1"));
35 | assertTrue(Cookies.isIP("::"));
36 | assertTrue(Cookies.isIP("::192.168.0.1"));
37 | assertTrue(Cookies.isIP("::FFFF:192.168.0.1"));
38 | assertFalse(Cookies.isIP("202.test.com"));
39 | assertFalse(Cookies.isIP("163.com"));
40 | assertFalse(Cookies.isIP("163.ac"));
41 | }
42 |
43 | @Test
44 | public void match() throws Exception {
45 | Cookie cookie = new Cookie("test.com", "/", "test", "value", 0, false, false);
46 | assertTrue(Cookies.match(cookie, "http", "test.com", "/test/"));
47 | assertTrue(Cookies.match(cookie, "http", "www.test.com", "/test/"));
48 |
49 | // https
50 | cookie = new Cookie("test.com", "/", "test", "value", 0, true, false);
51 | assertFalse(Cookies.match(cookie, "http", "test.com", "/test/"));
52 | assertTrue(Cookies.match(cookie, "https", "test.com", "/test/"));
53 |
54 | cookie = new Cookie("test.com", "/", "test", "value", 0, false, true);
55 | assertTrue(Cookies.match(cookie, "http", "test.com", "/test/"));
56 | assertFalse(Cookies.match(cookie, "http", "www.test.com", "/test/"));
57 |
58 | cookie = new Cookie("test.com", "/test/", "test", "value", 0, false, false);
59 | assertFalse(Cookies.match(cookie, "http", "test.com", "/"));
60 | assertTrue(Cookies.match(cookie, "http", "www.test.com", "/test/"));
61 |
62 | cookie = new Cookie("202.38.64.10", "/", "test", "value", 0, false, false);
63 | assertFalse(Cookies.match(cookie, "http", "38.64.10", "/"));
64 | assertTrue(Cookies.match(cookie, "http", "202.38.64.10", "/"));
65 | }
66 |
67 | @Test
68 | public void parseCookie() throws Exception {
69 | String cookieStr = "__bsi=11937048251853133038_00_0_I_R_181_0303_C02F_N_I_I_0;" +
70 | " expires=Thu, 16-Mar-17 03:39:29 GMT; domain=www.baidu.com; path=/";
71 | Cookie cookie = Cookies.parseCookie(cookieStr, "www.baidu.com", "/");
72 | assertNotNull(cookie);
73 | assertFalse(cookie.hostOnly());
74 | assertEquals("www.baidu.com", cookie.domain());
75 | assertEquals(1489635569000L, cookie.expiry());
76 | assertEquals("11937048251853133038_00_0_I_R_181_0303_C02F_N_I_I_0", cookie.value());
77 | assertEquals("/", cookie.path());
78 | assertEquals("__bsi", cookie.name());
79 |
80 |
81 | cookieStr = "V2EX_TAB=\"2|1:0|10:1489639030|8:V2EX_TAB|4:YWxs|94149dfee574a182c7a43cbcb752230e9e09ca44173293ca6ab446e9e1754598\";" +
82 | " expires=Thu, 30 Mar 2017 04:37:10 GMT; httponly; Path=/";
83 | cookie = Cookies.parseCookie(cookieStr, "www.v2ex.com", "/");
84 | assertNotNull(cookie);
85 | assertEquals("www.v2ex.com", cookie.domain());
86 | assertTrue(cookie.hostOnly());
87 | assertEquals(1490848630000L, cookie.expiry());
88 | assertEquals("/", cookie.path());
89 | assertEquals("V2EX_TAB", cookie.name());
90 |
91 | cookieStr = "YF-V5-G0=a2489c19ecf98bbe86a7bf6f0edcb071;Path=/";
92 | cookie = Cookies.parseCookie(cookieStr, "weibo.com", "/");
93 | assertNotNull(cookie);
94 | assertTrue(cookie.hostOnly());
95 | assertEquals("weibo.com", cookie.domain());
96 | assertEquals(0, cookie.expiry());
97 |
98 | cookieStr = "ALF=1521175171; expires=Friday, 16-Mar-2018 04:39:31 GMT; path=/; domain=.sina.com.cn";
99 | cookie = Cookies.parseCookie(cookieStr, "login.sina.com.cn", "/sso/");
100 | assertNotNull(cookie);
101 | assertEquals("sina.com.cn", cookie.domain());
102 | assertEquals(1521175171000L, cookie.expiry());
103 | assertEquals("/", cookie.path());
104 |
105 |
106 | cookie = Cookies.parseCookie("skey=@k4bPcIye6; PATH=/; DOMAIN=qq.com;", "ssl.ptlogin2.qq.com", "/");
107 | assertNotNull(cookie);
108 | assertEquals("qq.com", cookie.domain());
109 | }
110 | }
--------------------------------------------------------------------------------
/src/test/java/me/gv7/woodpecker/requests/util/URLUtilsTest.java:
--------------------------------------------------------------------------------
1 | package me.gv7.woodpecker.requests.util;
2 |
3 | import net.dongliu.commons.collection.Lists;
4 | import me.gv7.woodpecker.requests.Parameter;
5 | import me.gv7.woodpecker.requests.utils.URLUtils;
6 | import org.junit.Test;
7 |
8 | import java.net.URL;
9 | import java.util.List;
10 |
11 | import static java.nio.charset.StandardCharsets.UTF_8;
12 | import static org.junit.Assert.assertEquals;
13 |
14 | public class URLUtilsTest {
15 | @Test
16 | public void joinUrl() throws Exception {
17 | List> empty = Lists.of();
18 | assertEquals("http://www.test.com/", URLUtils.joinUrl(new URL("http://www.test.com/"),
19 | empty, UTF_8).toExternalForm());
20 | assertEquals("http://www.test.com/path", URLUtils.joinUrl(new URL("http://www.test.com/path"),
21 | empty, UTF_8).toExternalForm());
22 |
23 | assertEquals("http://www.test.com/path?t=v", URLUtils.joinUrl(new URL("http://www.test.com/path"),
24 | Lists.of(Parameter.of("t", "v")), UTF_8).toExternalForm());
25 | assertEquals("http://www.test.com/path?s=t&t=v", URLUtils.joinUrl(new URL("http://www.test.com/path?s=t"),
26 | Lists.of(Parameter.of("t", "v")), UTF_8).toExternalForm());
27 | assertEquals("http://www.test.com/path?t=v", URLUtils.joinUrl(new URL("http://www.test.com/path?"),
28 | Lists.of(Parameter.of("t", "v")), UTF_8).toExternalForm());
29 | assertEquals("http://www.test.com/path?t=v#seg", URLUtils.joinUrl(new URL("http://www.test.com/path#seg"),
30 | Lists.of(Parameter.of("t", "v")), UTF_8).toExternalForm());
31 | assertEquals("http://www.test.com/path?t=v#", URLUtils.joinUrl(new URL("http://www.test.com/path#"),
32 | Lists.of(Parameter.of("t", "v")), UTF_8).toExternalForm());
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/src/test/resources/jetty-logging.properties:
--------------------------------------------------------------------------------
1 | org.eclipse.jetty.LEVEL=WARN
--------------------------------------------------------------------------------
/src/test/resources/keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woodpecker-framework/woodpecker-requests/802997f1e68edb4d9eb9ea8ec29c8966d8cca77c/src/test/resources/keystore
--------------------------------------------------------------------------------