Coder Social home page Coder Social logo

ok2curl's Introduction

Ok2Curl Commit check Android Arsenal Release

Simply way to transform OkHttp requests into curl logs.

Supported OkHttp versions

Currently Ok2Curl requires OkHttp in version 4.x.

Usage

Add library to project dependencies. Library is hosted on Maven Central.

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.github.mrmike:ok2curl:0.8.0'
}

To start logging requests with Ok2Curl add interceptor to OkHttp client.

val client = OkHttpClient.Builder()
    .addInterceptor(CurlInterceptor(object : Logger {
        override fun log(message: String) {
            Log.v("Ok2Curl", message)
        }
    }))
    .build()

Result

With Ok2Curl set up correctly every executed request will be transformed into curl log e.g.

adb logcat -s "Ok2Curl"
curl -X GET -H "Cache-Control:max-stale=2147483647, only-if-cached" https://api.github.com/repos/vmg/redcarpet/issues?state=closed

Network interceptors

By default Ok2Curl uses application interceptors from OkHttp which is adequate for most cases. But sometimes you may want to use network interceptor e.g. to log Cookies set via CookieHandler. In such a case add interceptor the same way as below:

val client = OkHttpClient.Builder()
    .addNetworkInterceptor(CurlInterceptor(logger))
    .build()

To get know more about Interceptor in OkHttp take a look here: https://github.com/square/okhttp/wiki/Interceptors

Configuration

CurlInterceptor accepts an optional configuration object. With Configuration you can specify various options like:

  • header modifiers - custom logic for modifying header values
  • components - list of required command components
  • flags - optional curl flags
  • limit - bytes limit for body
  • delimiter for command components
class Configuration(
    val headerModifiers: List<HeaderModifier> = emptyList(),
    val components: List<CommandComponent> = CommandComponent.DEFAULT,
    val flags: Flags = Flags.EMPTY,
    val limit: Long = 1024L * 1024L,
    val delimiter: String = " "
)

Header modifiers

Ok2Curl allows you to modify any header before creating curl command. All you have to do is create your own modifier that implements HeaderModifier and add this modifier to CurlInterceptor. See sample for reference.

val modifier = BasicAuthorizationHeaderModifier(Base64Decoder())
val configuration = Configuration(headerModifiers = listOf(modifier))
val curlInterceptor = CurlInterceptor(AndroidLogger(), configuration)

Command Components

With Ok2Curl configuration you can specify a list of components for curl command. For instance, you can skip header, body, and flag components.

val components = listOf(Curl, Method, Url)
val configuration = Configuration(components = components)
val curlInterceptor = CurlInterceptor(AndroidLogger(), configuration)

As a result, CurlInterceptor will receive given simplified command

// Headers, body and flags are skipped
curl -X GET https://api.github.com/repos/vmg/redcarpet/issues?state=closed

Flags

Ok2Curl supports basic Curl options. To use options use the following code:

val flags = Flags.builder()
            .insecure()
            .connectTimeout(seconds = 120)
            .retry(5)
            .build()
val configuration = Configuration(flags = flags)
val curlInterceptor = CurlInterceptor(AndroidLogger(), configuration)

Since now every Curl command will start with curl --insecure --connect-timeout 120 --retry 5...

Supported options

  • --insecure
  • --max-time seconds
  • --connect-timeout seconds
  • --retry num
  • --compressed
  • --location

If would like to support any new options please feel free to open PR. A full list of curl options is available here.

License

Copyright 2018 Michał Moczulski

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

ok2curl's People

Contributors

flocsy avatar friederbluemle avatar jacek-marchwicki avatar mirland avatar mrmike avatar paour avatar swankjesse avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ok2curl's Issues

Escape `"` in the the headers

From backend I'm receiving a header like this: etag: "estoesunapruebadeetag" the " are part of the etag.

OkHttp when I call this endpoint again it adds this header: If-None-Match: "estoesunapruebadeetag".

But on curl I see this: -H "If-None-Match:"estoesunapruebadeetag"" when it should be -H "If-None-Match:\"estoesunapruebadeetag\"". The " should be escaped.

Put URL and body before headers

Hi and thanks for the lib,

I'm using this lib in my project to have HTTP calls logged and be able to reproduce them and import them in Postman. It works great !
But it's quite hard to find the call we are looking for because every request log start with the same text :

curl -X GET -H "Authorization:Bearer <a very looonnngg token>" -H "<some more headers>: <some more headers values>" "https://<the url we are looking for>"

So we are still using a "standard" OkHttp logger to get the URL readable easily.

Would it be possible to change the order of arguments in the curl command to :

  • the method
  • the url
  • the body
  • headers

Ex :
curl -X GET "https://example.com/endpoint" -d "a body" -H "header1: foo" -H "header2: bar"

unable to build

I'm not able to sync gradle.

Error:Dependency com.github.mrmike:ok2curl:0.2.0 on project app resolves to an APK archive which is not supported as a compilation dependency.

Were older versions removed from maven central?

I've been using 0.5.0 for a while now. All of a sudden today when running a build, I get:

* What went wrong:
Execution failed for task ':app:androidDependencies'.
> Could not resolve all artifacts for configuration ':app:prodDebugCompileClasspath'.
   > Could not find ok2curl-0.5.0.jar (com.github.mrmike:ok2curl:0.5.0).
     Searched in the following locations:
         https://plugins.gradle.org/m2/com/github/mrmike/ok2curl/0.5.0/ok2curl-0.5.0.jar

I looked at maven central via https://central.sonatype.com/artifact/com.github.mrmike/ok2curl/versions and https://mvnrepository.com/artifact/com.github.mrmike/ok2curl and only see version 0.7.0 and 0.8.0.

Were older versions removed?

v0.2.4 - broken build

after upgrading from v0.2.3 to v0.2.4

...
:app:transformClassesWithDexForLiveDebug
Dex: Error converting bytecode to dex:
Cause: Dex cannot parse version 52 byte code.
This is caused by library dependencies that have been compiled using Java 8 or above.
If you are using the 'java' gradle plugin in a library submodule add
targetCompatibility = '1.7'
sourceCompatibility = '1.7'
to that submodule's build.gradle file.
    UNEXPECTED TOP-LEVEL EXCEPTION:
    java.lang.RuntimeException: Exception parsing classes
        at com.android.dx.command.dexer.Main.processClass(Main.java:761)
        at com.android.dx.command.dexer.Main.processFileBytes(Main.java:727)
        at com.android.dx.command.dexer.Main.access$1200(Main.java:87)
        at com.android.dx.command.dexer.Main$FileBytesConsumer.processFileBytes(Main.java:1655)
        at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
        at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
        at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
        at com.android.dx.command.dexer.Main.processOne(Main.java:681)
        at com.android.dx.command.dexer.Main.processAllFiles(Main.java:578)
        at com.android.dx.command.dexer.Main.runMonoDex(Main.java:315)
        at com.android.dx.command.dexer.Main.run(Main.java:286)
        at com.android.builder.internal.compiler.DexWrapper.run(DexWrapper.java:52)
        at com.android.builder.core.AndroidBuilder$2.call(AndroidBuilder.java:1511)
        at com.android.builder.core.AndroidBuilder$2.call(AndroidBuilder.java:1507)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
    Caused by: com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
        at com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)
        at com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
        at com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)
        at com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)
        at com.android.dx.command.dexer.Main.parseClass(Main.java:773)
        at com.android.dx.command.dexer.Main.access$1600(Main.java:87)
        at com.android.dx.command.dexer.Main$ClassParserTask.call(Main.java:1694)
        at com.android.dx.command.dexer.Main.processClass(Main.java:758)
        ... 17 more

1 error; aborting
:app:transformClassesWithDexForLiveDebug FAILED

I have only one module (android application)

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }

NPE when calling MediaType.toString()

I just got this error:

10-13 12:08:27.317 1889-1912/? E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime: Process: my.package.name, PID: 1889
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.squareup.okhttp.MediaType.toString()' on a null object reference
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at com.moczul.ok2curl.CurlBuilder.<init>(CurlBuilder.java:35)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at com.moczul.ok2curl.CurlInterceptor.intercept(CurlInterceptor.java:31)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:221)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:195)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at com.squareup.okhttp.Call.access$100(Call.java:34)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:162)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
10-13 12:08:27.317 1889-1912/? E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:818)

I used OkHttp Version 2.5 and Ok2Curl 0.0.2.

Invalid handling of multiple headers of same name

My request is having two headers of the same name:

Cookie: JSESSIONID=....
Cookie: SOMETOKEN=....; OTHERTOKEN=....

This is correct with respect to HTTP protocol. However, CurlBuilder will take only the last header, because it is using a map with unique keys for header names:

    public CurlBuilder(Request request, long limit) {
       ...

        final Headers headers = request.headers();
        for (int i = 0; i < headers.size(); i++) {
            \\ MG: If there was already a header with same name it will be overwritten here
            this.headers.put(headers.name(i), headers.value(i));
        }
    }

Recognize Basic Authorization

In case request contains Authorization header of Basic type, e.g.,

Authorizaton: Basic bWFjaWVrOnRham5laGFzbG8xMjM=

would it be possible to have the following

curl -u maciej:tajnehaslo123 ...

?

Tips: not work for okhttp_3.x version

System.err:
Caused by: java.lang.ClassCastException: okhttp3.Headers cannot be cast to java.lang.Iterable

Because of:
okhttp3.Headers will extends Iterable until after okttp_4.x.

Maybe need add to README.

Missing from Jcenter

I cannot find the repo in jcenter, I tried this url and it looks like it's missing. Is it available on it? I'm using jitpack and it's working fine.

I saw that the remote was changed in this commit 10a27fc

Cookies added by CookieHandler don't show up as headers in the ok2curl-output

In an app I bridge cookies between the WebView and okhttp. This is done by setting a cookie-handler on the okhttp-client. These cookies, however, do not show up as headers in the requests that are printed.

example cookie handler & request (httpbin here simply echos the cookies it receives).

public class Ok2CurlCookieDemo {

    static final String tag = "Ok2CurlCookieDemo";

    private Ok2CurlCookieDemo() {
    }

    public static class FooBarCookieHandler extends CookieHandler {

        @Override
        public Map<String, List<String>> get(final URI uri, final Map<String, List<String>> requestHeaders) throws IOException {
            final Map<String, List<String>> result = Maps.newHashMap();
            final ArrayList<String> value = Lists.newArrayList("foo=bar; banana=rama;");
            result.put("Cookie", value);
            return result;
        }

        @Override
        public void put(final URI uri, final Map<String, List<String>> responseHeaders) throws IOException {

        }
    }

    public static void doRequest() {

        final OkHttpClient okHttpClient = new OkHttpClient();

        okHttpClient.setCookieHandler(new FooBarCookieHandler());
        Ok2Curl.set(okHttpClient);

        okHttpClient
                .newCall(new Request.Builder().url("http://httpbin.org/cookies").build())
                .enqueue(new Callback() {
                    @Override
                    public void onFailure(final Request request, final IOException e) {

                    }

                    @Override
                    public void onResponse(final Response response) throws IOException {
                        Log.d(tag, "httpbin got cookies: " +  response.body().string());
                    }
                });
    }
}

outputs:

10-16 10:39:49.350 1586-1608/? D/Ok2Curl: curl -X GET http://httpbin.org/cookies
10-16 10:39:49.556 1586-1608/? D/Ok2CurlCookieDemo: httpbin got cookies: {
10-16 10:39:49.556 1586-1608/? D/Ok2CurlCookieDemo:   "cookies": {
10-16 10:39:49.556 1586-1608/? D/Ok2CurlCookieDemo:     "banana": "rama", 
10-16 10:39:49.556 1586-1608/? D/Ok2CurlCookieDemo:     "foo": "bar"
10-16 10:39:49.556 1586-1608/? D/Ok2CurlCookieDemo:   }
10-16 10:39:49.556 1586-1608/? D/Ok2CurlCookieDemo: }

HTTP request body should not be URL encoded

For the following HTTP Request:

POST https://iamakamai.sqaextranet.akamai.com/ids-sso-config/restricted/idp/reminders http/1.1
Content-Type: application/x-www-form-urlencoded
INFO: Content-Length: 54
when=2017-09-26T14%3A20%3A19.425%2B02%3A00&force=false

Ok2Curl logs invalid curl command:

Ok2Curl: curl -X POST -H "Content-Type:application/x-www-form-urlencoded" -H "Content-Length:54" -H "Host:" -H "Accept-Encoding:gzip" -H "User-Agent:okhttp/3.8.0" -d 'when=2017-09-26T14%3A17%3A57.823%2B02%3A00&force=false'  https://server.com/reminders 

It is invalid because the HTTP request body under "-d" is already URL encoded. It should not be, because curl will encode it anyway.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.