Skip to content

Commit

Permalink
Merge pull request #85 from yvasyliev/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
yvasyliev committed Jan 2, 2022
2 parents 192ee80 + b0cb997 commit 3edef98
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ This library uses the next third-party dependencies:
<dependency>
<groupId>com.github.yvasyliev</groupId>
<artifactId>java-vk-bots-longpoll-api</artifactId>
<version>3.1.0</version>
<version>3.1.1</version>
</dependency>
```
4. Extend `LongPollBot` class and override necessary methods:
Expand Down
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<groupId>com.github.yvasyliev</groupId>
<artifactId>java-vk-bots-longpoll-api</artifactId>
<packaging>jar</packaging>
<version>3.1.0</version>
<version>3.1.1</version>
<name>Java VK Bots Long Poll API</name>
<description>A Java library to create VK bots using Bots Long Poll API</description>
<url>https://github.com/yvasyliev/java-vk-bots-long-poll-api</url>
Expand Down Expand Up @@ -42,9 +42,9 @@
<version>1.14.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.32</version>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.0</version>
<scope>test</scope>
</dependency>
<dependency>
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/api/longpoll/bots/http/HttpRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,22 @@ public interface HttpRequest {
* @return HTTP request multipart form data.
*/
MultipartFormData getMultipartFormData();

/**
* Whether this request has params.
*
* @return <b>true</b> if this request has params, <b>false</b> otherwise.
*/
default boolean hasParams() {
return getParams() != null && !getParams().isEmpty();
}

/**
* Whether this request has Multipart Form Data.
*
* @return <b>true</b> if this request has Multipart Form Data, <b>false</b> otherwise.
*/
default boolean hasMultipartFormData() {
return getMultipartFormData() != null;
}
}
6 changes: 1 addition & 5 deletions src/main/java/api/longpoll/bots/http/HttpResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,12 @@ public String getBody() {
return body;
}

private String hideSensitiveData(String sensitiveData) {
return sensitiveData.replaceAll("\"key\":\"\\w+\"", "\"key\":\"****************************************\"");
}

@Override
public String toString() {
return String.format(
"Status Code=%d, Body=%s",
statusCode,
hideSensitiveData(body)
body
);
}
}
116 changes: 116 additions & 0 deletions src/main/java/api/longpoll/bots/http/impl/DefaultHttpClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package api.longpoll.bots.http.impl;

import api.longpoll.bots.http.HttpClient;
import api.longpoll.bots.http.HttpRequest;
import api.longpoll.bots.http.HttpResponse;
import api.longpoll.bots.http.MultipartFormData;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

/**
* Default implementation of HTTP client.
*/
public class DefaultHttpClient implements HttpClient {
/**
* New line.
*/
private static final String CRLF = "\r\n";

@Override
public HttpResponse execute(HttpRequest httpRequest) throws IOException {
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = (HttpURLConnection) new URL(httpRequest.getUrl()).openConnection();
httpURLConnection.setRequestMethod(httpRequest.getRequestMethod());
httpURLConnection.setDoOutput(true);

if (httpRequest.hasParams()) {
try (DataOutputStream output = new DataOutputStream(httpURLConnection.getOutputStream())) {
output.writeBytes(toUrlParams(httpRequest.getParams()));
output.flush();
}
} else if (httpRequest.hasMultipartFormData()) {
MultipartFormData multipartFormData = httpRequest.getMultipartFormData();
String boundary = UUID.randomUUID().toString();
httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(httpURLConnection.getOutputStream(), StandardCharsets.UTF_8), true)) {
writer.append("--").append(boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"").append(multipartFormData.getKey()).append("\"; filename=\"").append(multipartFormData.getFilename()).append("\"").append(CRLF);
writer.append("Content-Type: ").append(HttpURLConnection.guessContentTypeFromName(multipartFormData.getFilename())).append(CRLF);
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
writer.append(CRLF);
writer.flush();

copy(multipartFormData.getInputStream(), httpURLConnection.getOutputStream());

writer.append(CRLF);
writer.append("--").append(boundary).append("--").append(CRLF);
writer.flush();
}
}

try (BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()))) {
return new HttpResponse(
httpURLConnection.getResponseCode(),
reader.lines().collect(Collectors.joining())
);
}
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
}

/**
* Converts params Map to URL params.
*
* @param params params Map.
* @return URL params.
* @throws UnsupportedEncodingException when failed to encode params.
*/
private String toUrlParams(Map<String, String> params) throws UnsupportedEncodingException {
List<String> paramsList = new ArrayList<>(params.size());
for (Map.Entry<String, String> entry : params.entrySet()) {
paramsList.add(encode(entry.getKey()) + "=" + encode(entry.getValue()));
}
return String.join("&", paramsList);
}

/**
* Encodes string value with UTF-8 encoding.
*
* @param s string to encode.
* @return encoded string.
* @throws UnsupportedEncodingException when failed to encode.
*/
private String encode(String s) throws UnsupportedEncodingException {
return URLEncoder.encode(s, "UTF-8");
}

/**
* Reads data from {@link InputStream} and writes to {@link OutputStream}.
*
* @param from source.
* @param to target.
* @throws IOException when errors occur.
*/
private void copy(InputStream from, OutputStream to) throws IOException {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = from.read(buffer)) != -1) {
to.write(buffer, 0, bytesRead);
}
to.flush();
}
}
35 changes: 16 additions & 19 deletions src/main/java/api/longpoll/bots/methods/impl/VkMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import api.longpoll.bots.http.HttpRequest;
import api.longpoll.bots.http.HttpResponse;
import api.longpoll.bots.http.MultipartFormData;
import api.longpoll.bots.http.impl.JsoupHttpClient;
import api.longpoll.bots.http.impl.DefaultHttpClient;
import api.longpoll.bots.reader.impl.PropertiesReader;
import api.longpoll.bots.validator.Validator;
import api.longpoll.bots.validator.VkResponseValidator;
Expand All @@ -22,7 +22,6 @@
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
* Executes generic HTTP request to VK API.
Expand Down Expand Up @@ -61,7 +60,8 @@ public abstract class VkMethod<Response> implements HttpRequest {
/**
* HTTP client.
*/
private final HttpClient httpClient = new JsoupHttpClient();
private final HttpClient httpClient = new DefaultHttpClient();

/**
* Validator to check if VK API response is valid.
*/
Expand Down Expand Up @@ -163,21 +163,18 @@ public Gson getGson() {
return gson;
}

private Map<String, String> hideSensitiveData(Map<String, String> sensitiveData) {
return sensitiveData.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> {
switch (entry.getKey()) {
case "access_token":
case "key":
return entry.getValue().replaceAll(".", "*");
default:
return entry.getValue();
}
}
));
/**
* Hides <i>access_token</i> from logging.
*
* @return non-sensitive params.
*/
private Map<String, String> getNonSensitiveParams() {
return new HashMap<String, String>(params) {{
computeIfPresent(
"access_token",
(key, value) -> value.replaceAll(".", "*")
);
}};
}

@Override
Expand All @@ -186,7 +183,7 @@ public String toString() {
"Method=%s, URL=%s, Params=%s",
getRequestMethod(),
getUrl(),
hideSensitiveData(params)
getNonSensitiveParams()
);
}
}
4 changes: 0 additions & 4 deletions src/test/resource/log4j.properties

This file was deleted.

13 changes: 13 additions & 0 deletions src/test/resource/log4j2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="stdout" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="ALL">
<AppenderRef ref="stdout"/>
</Root>
</Loggers>
</Configuration>

0 comments on commit 3edef98

Please sign in to comment.