stream improvements

This commit is contained in:
simon 2020-10-08 15:43:57 +03:00
parent e8fc5959de
commit bde5ae822b
4 changed files with 297 additions and 44 deletions

View file

@ -4,6 +4,7 @@ import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.model.Response;
import com.github.scribejava.core.model.Verb;
import net.osmand.PlatformUtil;
import net.osmand.osm.oauth.IInputStreamHttpClient;
import net.osmand.osm.oauth.OsmOAuthAuthorizationClient;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -72,12 +73,13 @@ public class NetworkUtils {
HttpURLConnection conn;
if (client != null && client.isValidToken()){
OAuthRequest req = new OAuthRequest(Verb.POST, urlText);
req.setPayload(prepareStream(formName,fileToUpload,gzip));
client.getService().signRequest(client.getAccessToken(), req);
req.addHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
try {
IInputStreamHttpClient service = (IInputStreamHttpClient) client.getService();
service.execute(service.getUserAgent(), req.getHeaders(), req.getVerb(), req.getCompleteUrl(), fileToUpload);
Response r = client.getService().execute(req);
if(r.getCode() != 200){
if (r.getCode() != 200) {
return r.getBody();
}
return null;
@ -100,7 +102,29 @@ public class NetworkUtils {
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); //$NON-NLS-1$ //$NON-NLS-2$
conn.setRequestProperty("User-Agent", "OsmAnd"); //$NON-NLS-1$ //$NON-NLS-2$
OutputStream ous = conn.getOutputStream();
ous.write(prepareStream(formName,fileToUpload,gzip));
ous.write(("--" + BOUNDARY + "\r\n").getBytes());
String filename = fileToUpload.getName();
if (gzip) {
filename += ".gz";
}
ous.write(("content-disposition: form-data; name=\"" + formName + "\"; filename=\"" + filename + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$
InputStream fis = new FileInputStream(fileToUpload);
BufferedInputStream bis = new BufferedInputStream(fis, 20 * 1024);
ous.flush();
if (gzip) {
GZIPOutputStream gous = new GZIPOutputStream(ous, 1024);
Algorithms.streamCopy(bis, gous);
gous.flush();
gous.finish();
} else {
Algorithms.streamCopy(bis, ous);
}
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.flush();
Algorithms.closeStream(bis);
Algorithms.closeStream(ous);
log.info("Finish uploading file " + fileToUpload.getName());
log.info("Response code and message : " + conn.getResponseCode() + " " + conn.getResponseMessage());
if(conn.getResponseCode() != 200){
@ -131,46 +155,6 @@ public class NetworkUtils {
}
}
private static byte[] prepareStream(String formName, File fileToUpload, boolean gzip) {
try {
ByteArrayOutputStream ous = new ByteArrayOutputStream();
// for (String key : additionalMapData.keySet()) {
// ous.write(("--" + BOUNDARY + "\r\n").getBytes());
// ous.write(("content-disposition: form-data; name=\"" + key + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
// ous.write((additionalMapData.get(key) + "\r\n").getBytes());
// }
ous.write(("--" + BOUNDARY + "\r\n").getBytes());
String filename = fileToUpload.getName();
if (gzip) {
filename += ".gz";
}
ous.write(("content-disposition: form-data; name=\"" + formName + "\"; filename=\"" + filename + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$
InputStream fis = new FileInputStream(fileToUpload);
BufferedInputStream bis = new BufferedInputStream(fis, 20 * 1024);
ous.flush();
if (gzip) {
GZIPOutputStream gous = new GZIPOutputStream(ous, 1024);
Algorithms.streamCopy(bis, gous);
gous.flush();
gous.finish();
gous.close();
} else {
Algorithms.streamCopy(bis, ous);
}
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.flush();
Algorithms.closeStream(bis);
Algorithms.closeStream(ous);
return ous.toByteArray();
} catch (IOException e) {
log.error(e);
}
return new byte[0];
}
public static void setProxy(String host, int port) {
if(host != null && port > 0) {
InetSocketAddress isa = new InetSocketAddress(host, port);
@ -179,7 +163,6 @@ public class NetworkUtils {
proxy = null;
}
}
public static Proxy getProxy() {
return proxy;
}

View file

@ -0,0 +1,7 @@
package net.osmand.osm.oauth;
import com.github.scribejava.core.httpclient.HttpClient;
public interface IInputStreamHttpClient extends HttpClient {
String getUserAgent();
}

View file

@ -0,0 +1,260 @@
package net.osmand.osm.oauth;
import com.github.scribejava.core.exceptions.OAuthException;
import com.github.scribejava.core.httpclient.HttpClient;
import com.github.scribejava.core.httpclient.jdk.JDKHttpClientConfig;
import com.github.scribejava.core.httpclient.jdk.JDKHttpFuture;
import com.github.scribejava.core.httpclient.multipart.MultipartPayload;
import com.github.scribejava.core.httpclient.multipart.MultipartUtils;
import com.github.scribejava.core.model.*;
import net.osmand.util.Algorithms;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public class OsmAndJDKHttpClient implements IInputStreamHttpClient {
private static final String BOUNDARY = "CowMooCowMooCowCowCow";
private final JDKHttpClientConfig config;
public OsmAndJDKHttpClient() {
this(JDKHttpClientConfig.defaultConfig());
}
public OsmAndJDKHttpClient(JDKHttpClientConfig clientConfig) {
config = clientConfig;
}
@Override
public void close() {
}
@Override
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
byte[] bodyContents, OAuthAsyncRequestCallback<T> callback, OAuthRequest.ResponseConverter<T> converter) {
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.BYTE_ARRAY, bodyContents, callback,
converter);
}
@Override
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
MultipartPayload bodyContents, OAuthAsyncRequestCallback<T> callback,
OAuthRequest.ResponseConverter<T> converter) {
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.MULTIPART, bodyContents, callback,
converter);
}
@Override
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
String bodyContents, OAuthAsyncRequestCallback<T> callback, OAuthRequest.ResponseConverter<T> converter) {
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.STRING, bodyContents, callback,
converter);
}
@Override
public <T> Future<T> executeAsync(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
File bodyContents, OAuthAsyncRequestCallback<T> callback, OAuthRequest.ResponseConverter<T> converter) {
return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.STREAM, bodyContents, callback,
converter);
}
private <T> Future<T> doExecuteAsync(String userAgent, Map<String, String> headers, Verb httpVerb,
String completeUrl, BodyType bodyType, Object bodyContents, OAuthAsyncRequestCallback<T> callback,
OAuthRequest.ResponseConverter<T> converter) {
try {
final Response response = doExecute(userAgent, headers, httpVerb, completeUrl, bodyType, bodyContents);
@SuppressWarnings("unchecked")
final T t = converter == null ? (T) response : converter.convert(response);
if (callback != null) {
callback.onCompleted(t);
}
return new JDKHttpFuture<>(t);
} catch (IOException | RuntimeException e) {
if (callback != null) {
callback.onThrowable(e);
}
return new JDKHttpFuture<>(e);
}
}
@Override
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
byte[] bodyContents) throws InterruptedException, ExecutionException, IOException {
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.BYTE_ARRAY, bodyContents);
}
@Override
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
MultipartPayload multipartPayloads) throws InterruptedException, ExecutionException, IOException {
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.MULTIPART, multipartPayloads);
}
@Override
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
String bodyContents) throws InterruptedException, ExecutionException, IOException {
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.STRING, bodyContents);
}
@Override
public Response execute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
File bodyContents) throws InterruptedException, ExecutionException, IOException {
return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.STREAM, bodyContents);
}
private Response doExecute(String userAgent, Map<String, String> headers, Verb httpVerb, String completeUrl,
BodyType bodyType, Object bodyContents) throws IOException {
final URL url = new URL(completeUrl);
final HttpURLConnection connection;
if (config.getProxy() == null) {
connection = (HttpURLConnection) url.openConnection();
} else {
connection = (HttpURLConnection) url.openConnection(config.getProxy());
}
connection.setInstanceFollowRedirects(config.isFollowRedirects());
connection.setRequestMethod(httpVerb.name());
if (config.getConnectTimeout() != null) {
connection.setConnectTimeout(config.getConnectTimeout());
}
if (config.getReadTimeout() != null) {
connection.setReadTimeout(config.getReadTimeout());
}
addHeaders(connection, headers, userAgent);
if (httpVerb.isPermitBody()) {
bodyType.setBody(connection, bodyContents, httpVerb.isRequiresBody());
}
try {
connection.connect();
final int responseCode = connection.getResponseCode();
return new Response(responseCode, connection.getResponseMessage(), parseHeaders(connection),
responseCode >= 200 && responseCode < 400 ? connection.getInputStream()
: connection.getErrorStream());
} catch (UnknownHostException e) {
throw new OAuthException("The IP address of a host could not be determined.", e);
}
}
@Override
public String getUserAgent() {
return "OsmandUserAgent";
}
private enum BodyType {
BYTE_ARRAY {
@Override
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
addBody(connection, (byte[]) bodyContents, requiresBody);
}
},
STREAM {
@Override
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
addBody(connection, (File) bodyContents, requiresBody);
}
},
MULTIPART {
@Override
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
addBody(connection, (MultipartPayload) bodyContents, requiresBody);
}
},
STRING {
@Override
void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException {
addBody(connection, ((String) bodyContents).getBytes(), requiresBody);
}
};
abstract void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody)
throws IOException;
}
private static Map<String, String> parseHeaders(HttpURLConnection conn) {
final Map<String, String> headers = new HashMap<>();
for (Map.Entry<String, List<String>> headerField : conn.getHeaderFields().entrySet()) {
final String key = headerField.getKey();
final String value = headerField.getValue().get(0);
if ("Content-Encoding".equalsIgnoreCase(key)) {
headers.put("Content-Encoding", value);
} else {
headers.put(key, value);
}
}
return headers;
}
private static void addHeaders(HttpURLConnection connection, Map<String, String> headers, String userAgent) {
for (Map.Entry<String, String> header : headers.entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
if (userAgent != null) {
connection.setRequestProperty(OAuthConstants.USER_AGENT_HEADER_NAME, userAgent);
}
}
private static void addBody(HttpURLConnection connection, File file, boolean requiresBody) throws IOException {
if (requiresBody) {
String filename = file.getName();
String formName = "file";
final OutputStream ous = prepareConnectionForBodyAndGetOutputStream(connection, 20 * 1024);
ous.write(("--" + BOUNDARY+"\r\n").getBytes());
InputStream stream = new FileInputStream(file);
ous.write(("content-disposition: form-data; name=\""+formName+"\"; filename=\"" + filename + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$
BufferedInputStream bis = new BufferedInputStream(stream, 20 * 1024);
ous.flush();
Algorithms.streamCopy(bis, ous);
ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$
ous.flush();
Algorithms.closeStream(bis);
Algorithms.closeStream(ous);
}
}
private static void addBody(HttpURLConnection connection, byte[] content, boolean requiresBody) throws IOException {
final int contentLength = content.length;
if (requiresBody || contentLength > 0) {
final OutputStream outputStream = prepareConnectionForBodyAndGetOutputStream(connection, contentLength);
if (contentLength > 0) {
outputStream.write(content);
}
}
}
private static void addBody(HttpURLConnection connection, MultipartPayload multipartPayload, boolean requiresBody)
throws IOException {
for (Map.Entry<String, String> header : multipartPayload.getHeaders().entrySet()) {
connection.setRequestProperty(header.getKey(), header.getValue());
}
if (requiresBody) {
final ByteArrayOutputStream os = MultipartUtils.getPayload(multipartPayload);
final int contentLength = os.size();
final OutputStream outputStream = prepareConnectionForBodyAndGetOutputStream(connection, contentLength);
if (contentLength > 0) {
os.writeTo(outputStream);
}
}
}
private static OutputStream prepareConnectionForBodyAndGetOutputStream(HttpURLConnection connection,
int contentLength) throws IOException {
connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(contentLength));
if (connection.getRequestProperty(CONTENT_TYPE) == null) {
connection.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);
}
connection.setDoOutput(true);
return connection.getOutputStream();
}
}

View file

@ -4,6 +4,8 @@ package net.osmand.osm.oauth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.builder.api.DefaultApi10a;
import com.github.scribejava.core.builder.api.OAuth1SignatureType;
import com.github.scribejava.core.httpclient.jdk.JDKHttpClient;
import com.github.scribejava.core.httpclient.jdk.JDKHttpClientConfig;
import com.github.scribejava.core.model.*;
import com.github.scribejava.core.oauth.OAuth10aService;
import net.osmand.PlatformUtil;
@ -26,6 +28,7 @@ public class OsmOAuthAuthorizationClient {
public OsmOAuthAuthorizationClient(String key, String secret) {
service = new ServiceBuilder(key)
.apiSecret(secret)
.httpClient(new OsmAndJDKHttpClient(JDKHttpClientConfig.defaultConfig()))
.callback("osmand-oauth://example.com/oauth")
.build(new OsmApi());
}