diff --git a/README.md b/README.md index 305b2d9..0dd7d69 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ dependencies { // snapshot version compile 'com.github.mrmike:Ok2Curl:master-SNAPSHOT' // or use specific version - compile 'com.github.mrmike:Ok2Curl:0.3.0' + compile 'com.github.mrmike:Ok2Curl:0.3.1' } ``` diff --git a/ok2curl/build.gradle b/ok2curl/build.gradle index d808fde..2f6c94e 100644 --- a/ok2curl/build.gradle +++ b/ok2curl/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'java' apply plugin: 'maven' group='com.github.mrmike' -version='0.3.0' +version='0.3.1' targetCompatibility = '1.7' sourceCompatibility = '1.7' diff --git a/ok2curl/src/main/java/com/moczul/ok2curl/CurlBuilder.java b/ok2curl/src/main/java/com/moczul/ok2curl/CurlBuilder.java index 99fad85..08c45bb 100644 --- a/ok2curl/src/main/java/com/moczul/ok2curl/CurlBuilder.java +++ b/ok2curl/src/main/java/com/moczul/ok2curl/CurlBuilder.java @@ -1,8 +1,11 @@ package com.moczul.ok2curl; +import com.moczul.ok2curl.modifier.HeaderModifier; + import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -30,10 +33,10 @@ public class CurlBuilder { private List
headers = new LinkedList<>(); public CurlBuilder(Request request) { - this(request, -1L); + this(request, -1L, Collections.emptyList()); } - public CurlBuilder(Request request, long limit) { + public CurlBuilder(Request request, long limit, List headerModifiers) { this.url = request.url().toString(); this.method = request.method(); final RequestBody body = request.body(); @@ -44,10 +47,24 @@ public CurlBuilder(Request request, long limit) { final Headers headers = request.headers(); for (int i = 0; i < headers.size(); i++) { - this.headers.add(new Header(headers.name(i), headers.value(i))); + final Header header = new Header(headers.name(i), headers.value(i)); + final Header modifiedHeader = modifyHeader(header, headerModifiers); + if (modifiedHeader != null) { + this.headers.add(modifiedHeader); + } } } + private Header modifyHeader(Header header, List headerModifiers) { + for (HeaderModifier modifier : headerModifiers) { + if (modifier.matches(header)) { + return modifier.modify(header); + } + } + + return header; + } + private String getContentType(RequestBody body) { final MediaType mediaType = body.contentType(); if (mediaType != null) { diff --git a/ok2curl/src/main/java/com/moczul/ok2curl/CurlInterceptor.java b/ok2curl/src/main/java/com/moczul/ok2curl/CurlInterceptor.java index 07a4cc5..7340748 100644 --- a/ok2curl/src/main/java/com/moczul/ok2curl/CurlInterceptor.java +++ b/ok2curl/src/main/java/com/moczul/ok2curl/CurlInterceptor.java @@ -1,43 +1,44 @@ package com.moczul.ok2curl; import com.moczul.ok2curl.logger.Loggable; +import com.moczul.ok2curl.modifier.HeaderModifier; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; -import java.io.IOException; - public class CurlInterceptor implements Interceptor { - private static final String TAG = "Ok2Curl"; private static final long DEFAULT_LIMIT = 1024L * 1024L; private final Loggable logger; private final long limit; + private final List headerModifiers = new ArrayList<>(); /** * Interceptor responsible for printing curl logs * * Logs are pushed to stdout with 1MB limit + * + * @param logger output of logging */ - public CurlInterceptor() { - this(new Loggable() { - @Override - public void log(String message) { - System.out.println(TAG + " " + message); - } - }); + public CurlInterceptor(Loggable logger) { + this(logger, DEFAULT_LIMIT, Collections.emptyList()); } /** * Interceptor responsible for printing curl logs * - * Logs are pushed to stdout with 1MB limit - * * @param logger output of logging + * @param headerModifiers list of header modifiers */ - public CurlInterceptor(Loggable logger) { - this(logger, DEFAULT_LIMIT); + public CurlInterceptor(Loggable logger, List headerModifiers) { + this(logger, DEFAULT_LIMIT, headerModifiers); } /** @@ -47,8 +48,19 @@ public CurlInterceptor(Loggable logger) { * @param limit limit maximal bytes logged, if negative - non limited */ public CurlInterceptor(Loggable logger, long limit) { + this(logger, limit, Collections.emptyList()); + } + + /** + * Interceptor responsible for printing curl logs + * @param logger output of logging + * @param limit limit maximal bytes logged, if negative - non limited + * @param headerModifiers list of header modifiers + */ + public CurlInterceptor(Loggable logger, long limit, List headerModifiers) { this.logger = logger; this.limit = limit; + this.headerModifiers.addAll(headerModifiers); } @Override @@ -56,7 +68,7 @@ public Response intercept(Chain chain) throws IOException { final Request request = chain.request(); final Request copy = request.newBuilder().build(); - final String curl = new CurlBuilder(copy, limit).build(); + final String curl = new CurlBuilder(copy, limit, headerModifiers).build(); logger.log(curl); diff --git a/ok2curl/src/main/java/com/moczul/ok2curl/modifier/HeaderModifier.java b/ok2curl/src/main/java/com/moczul/ok2curl/modifier/HeaderModifier.java new file mode 100644 index 0000000..94cf539 --- /dev/null +++ b/ok2curl/src/main/java/com/moczul/ok2curl/modifier/HeaderModifier.java @@ -0,0 +1,21 @@ +package com.moczul.ok2curl.modifier; + +import com.moczul.ok2curl.Header; + +/** + * HeaderModifier allow for changing header name/value before creating curl log + */ +public interface HeaderModifier { + + /** + * @param header + * @return true if header should be modified and false otherwise. + */ + boolean matches(Header header); + + /** + * @param header + * @return modified header or null to omit header in curl log + */ + Header modify(Header header); +} diff --git a/ok2curl/src/test/java/com/moczul/ok2curl/CurlBuilderTest.java b/ok2curl/src/test/java/com/moczul/ok2curl/CurlBuilderTest.java index 868017b..a12c847 100644 --- a/ok2curl/src/test/java/com/moczul/ok2curl/CurlBuilderTest.java +++ b/ok2curl/src/test/java/com/moczul/ok2curl/CurlBuilderTest.java @@ -1,6 +1,8 @@ package com.moczul.ok2curl; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; import java.util.concurrent.TimeUnit; diff --git a/ok2curl/src/test/java/com/moczul/ok2curl/util/HeaderModifierTest.java b/ok2curl/src/test/java/com/moczul/ok2curl/util/HeaderModifierTest.java new file mode 100644 index 0000000..08af7f4 --- /dev/null +++ b/ok2curl/src/test/java/com/moczul/ok2curl/util/HeaderModifierTest.java @@ -0,0 +1,83 @@ +package com.moczul.ok2curl.util; + +import com.moczul.ok2curl.CurlBuilder; +import com.moczul.ok2curl.Header; +import com.moczul.ok2curl.modifier.HeaderModifier; + +import org.junit.Test; + +import java.util.Collections; +import java.util.List; + +import okhttp3.Request; + +import static junit.framework.Assert.assertEquals; + +public class HeaderModifierTest { + + private final HeaderModifier cookieHeaderModifier = new HeaderModifier() { + + @Override + public boolean matches(Header header) { + return "Cookie".equals(header.name()); + } + + @Override + public Header modify(Header header) { + return new Header(header.name(), "modifiedCookieValue"); + } + }; + + private final HeaderModifier nullHeaderModifier = new HeaderModifier() { + + @Override + public boolean matches(Header header) { + return true; + } + + @Override + public Header modify(Header header) { + return null; + } + }; + + @Test + public void curlCommand_shouldContains_modifiedHeader() throws Exception { + final Request request = new Request.Builder() + .url("http://example.com/") + .header("Cookie", "FIRST=foo") + .build(); + + final List modifiers = Collections.singletonList(cookieHeaderModifier); + final String command = new CurlBuilder(request, -1L, modifiers).build(); + + assertEquals("curl -X GET -H \"Cookie:modifiedCookieValue\" http://example.com/", command); + } + + @Test + public void curlCommand_shouldNotBeModified_ifDoesNotContainMatchingHeader() throws Exception { + final Request request = new Request.Builder() + .url("http://example.com/") + .header("Accept", "application/json") + .build(); + final List modifiers = Collections.singletonList(cookieHeaderModifier); + + final String command = new CurlBuilder(request, -1L, modifiers).build(); + + assertEquals("curl -X GET -H \"Accept:application/json\" http://example.com/", command); + } + + @Test + public void curlCommand_shouldNotContainsAnyHeaders_forNullHeaderModifier() throws Exception { + final Request request = new Request.Builder() + .url("http://example.com/") + .header("Cookie", "FIRST=foo") + .header("Accept", "application/json") + .build(); + + final List modifiers = Collections.singletonList(nullHeaderModifier); + final String command = new CurlBuilder(request, -1L, modifiers).build(); + + assertEquals(command, "curl -X GET http://example.com/", command); + } +} diff --git a/sample/build.gradle b/sample/build.gradle index c728959..d69164f 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -49,4 +49,5 @@ dependencies { compile 'com.android.support:appcompat-v7:23.1.1' testCompile 'junit:junit:4.12' + testCompile 'org.mockito:mockito-core:1.10.19' } diff --git a/sample/src/main/java/com/moczul/sample/MainActivity.java b/sample/src/main/java/com/moczul/sample/MainActivity.java index 396b7c3..aa46491 100644 --- a/sample/src/main/java/com/moczul/sample/MainActivity.java +++ b/sample/src/main/java/com/moczul/sample/MainActivity.java @@ -7,6 +7,12 @@ import android.widget.TextView; import com.moczul.ok2curl.CurlBuilder; +import com.moczul.ok2curl.modifier.HeaderModifier; +import com.moczul.sample.modifier.Base64Decoder; +import com.moczul.sample.modifier.BasicAuthorizationHeaderModifier; + +import java.util.Collections; +import java.util.List; public class MainActivity extends AppCompatActivity implements View.OnClickListener { @@ -21,6 +27,7 @@ protected void onCreate(Bundle savedInstanceState) { findViewById(R.id.get_request).setOnClickListener(this); findViewById(R.id.post_request).setOnClickListener(this); + findViewById(R.id.get_request_modified).setOnClickListener(this); } private void sendRequest(String type) { @@ -31,7 +38,10 @@ private void sendRequest(String type) { } private void displayCurlLog(String type) { - final String curl = new CurlBuilder(RequestFactory.getRequest(type)).build(); + final BasicAuthorizationHeaderModifier modifier = new BasicAuthorizationHeaderModifier(new Base64Decoder()); + final List modifiers = Collections.singletonList(modifier); + + final String curl = new CurlBuilder(RequestFactory.getRequest(type), -1L, modifiers).build(); curlLog.setText(curl); } @@ -46,6 +56,10 @@ public void onClick(View v) { sendRequest(RequestFactory.TYPE_POST); displayCurlLog(RequestFactory.TYPE_POST); break; + case R.id.get_request_modified: + sendRequest(RequestFactory.TYPE_GET_MODIFIED); + displayCurlLog(RequestFactory.TYPE_GET_MODIFIED); + break; default: throw new IllegalArgumentException("Invalid view id"); } diff --git a/sample/src/main/java/com/moczul/sample/RequestFactory.java b/sample/src/main/java/com/moczul/sample/RequestFactory.java index 1f5f1a6..ceecebf 100644 --- a/sample/src/main/java/com/moczul/sample/RequestFactory.java +++ b/sample/src/main/java/com/moczul/sample/RequestFactory.java @@ -9,6 +9,7 @@ public class RequestFactory { public static final String TYPE_GET = "type_get"; public static final String TYPE_POST = "type_post"; + public static final String TYPE_GET_MODIFIED = "type_get_modified"; private static final String NEW_REPO_BODY = "{" + " \"name\": \"Hello-World\"," + @@ -34,12 +35,21 @@ public static Request samplePostRequest() { .build(); } + public static Request modifiedGetRequest() { + return new Request.Builder() + .url("https://api.github.com/repos/vmg/redcarpet/issues?state=closed") + .header("Authorization", "Basic bWFjaWVrOnRham5laGFzbG8xMjM=") + .build(); + } + public static Request getRequest(String type) { switch (type) { case TYPE_GET: return sampleGetRequest(); case TYPE_POST: return samplePostRequest(); + case TYPE_GET_MODIFIED: + return modifiedGetRequest(); default: throw new IllegalArgumentException("Invalid request type"); } diff --git a/sample/src/main/java/com/moczul/sample/RequestService.java b/sample/src/main/java/com/moczul/sample/RequestService.java index 8945846..b6506a8 100644 --- a/sample/src/main/java/com/moczul/sample/RequestService.java +++ b/sample/src/main/java/com/moczul/sample/RequestService.java @@ -4,8 +4,13 @@ import android.content.Intent; import com.moczul.ok2curl.CurlInterceptor; +import com.moczul.ok2curl.modifier.HeaderModifier; +import com.moczul.sample.modifier.Base64Decoder; +import com.moczul.sample.modifier.BasicAuthorizationHeaderModifier; import java.io.IOException; +import java.util.Collections; +import java.util.List; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -20,7 +25,10 @@ public RequestService() { @Override protected void onHandleIntent(Intent intent) { - final CurlInterceptor curlInterceptor = new CurlInterceptor(new AndroidLogger()); + final BasicAuthorizationHeaderModifier modifier = new BasicAuthorizationHeaderModifier(new Base64Decoder()); + final List modifiers = Collections.singletonList(modifier); + + final CurlInterceptor curlInterceptor = new CurlInterceptor(new AndroidLogger(), modifiers); final OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(curlInterceptor) diff --git a/sample/src/main/java/com/moczul/sample/modifier/Base64Decoder.java b/sample/src/main/java/com/moczul/sample/modifier/Base64Decoder.java new file mode 100644 index 0000000..2c5f154 --- /dev/null +++ b/sample/src/main/java/com/moczul/sample/modifier/Base64Decoder.java @@ -0,0 +1,11 @@ +package com.moczul.sample.modifier; + +import android.util.Base64; + +public class Base64Decoder { + + public String decode(String value) { + final byte[] decodedBytes = Base64.decode(value.getBytes(), Base64.DEFAULT); + return new String(decodedBytes); + } +} diff --git a/sample/src/main/java/com/moczul/sample/modifier/BasicAuthorizationHeaderModifier.java b/sample/src/main/java/com/moczul/sample/modifier/BasicAuthorizationHeaderModifier.java new file mode 100644 index 0000000..86a18da --- /dev/null +++ b/sample/src/main/java/com/moczul/sample/modifier/BasicAuthorizationHeaderModifier.java @@ -0,0 +1,26 @@ +package com.moczul.sample.modifier; + +import com.moczul.ok2curl.Header; +import com.moczul.ok2curl.modifier.HeaderModifier; + +public class BasicAuthorizationHeaderModifier implements HeaderModifier { + + private final Base64Decoder base64Decoder; + + public BasicAuthorizationHeaderModifier(Base64Decoder base64Decoder) { + this.base64Decoder = base64Decoder; + } + + @Override + public boolean matches(Header header) { + return "Authorization".equals(header.name()) + && header.value().startsWith("Basic"); + } + + @Override + public Header modify(Header header) { + final String valueToDecode = header.value().replace("Basic", "").trim(); + final String decodedHeaderValue = base64Decoder.decode(valueToDecode); + return new Header(header.name(), decodedHeaderValue); + } +} diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index ea7bc68..812c61e 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -22,6 +22,12 @@ android:layout_height="wrap_content" android:text="@string/sample_post_request" /> +