5

I wrote REST client using springs RestTemplate in java and in groovy using 'HTTPBuilder'. Both invocation took 10 second on my computer. In Postman and other tools this kind the same post request it took 300 ms.

This is simple invocation in groovy script. Essential is between BEGIN REST invocation and END REST invocation:

    @Grapes(
            @Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7')
    )


    import groovy.json.JsonOutput
    import groovy.json.internal.LazyMap
    import groovy.transform.ToString
    import groovyx.net.http.HTTPBuilder

    import static groovyx.net.http.ContentType.JSON
    import static groovyx.net.http.Method.POST


    HTTPBuilder http = new HTTPBuilder()
    Forechart forechart = new Forechart(dayInterval: 3, adultCount: 1, childCount: 0,
                                        flightList: [new Flight(departureStation: "WAW", arrivalStation: "CRL", date: new Date(2018, 06, 02))
                                                    ,new Flight(departureStation: "CRL", arrivalStation: "WAW", date: new Date(2018, 10, 26))])

    def jsonRequest = JsonOutput.toJson( forechart )
    LazyMap jsonResponse



    //BEGIN REST invocation
        println "Request: " + JsonOutput.prettyPrint(jsonRequest)
        long start = System.nanoTime()

        http.request( 'https://be.wizzair.com/7.15/Api/asset/farechart', POST, JSON ) { req ->
            body = jsonRequest
            headers.Accept = 'application/json'

            response.success = { resp, json ->
                assert resp.statusLine.statusCode == 200
                jsonResponse = json
            }

            response.'404' = {
                println 'Not found'
            }
        }

        long end = System.nanoTime() - start

        //println "Response: $jsonResponse"
        println "\nDuration: " + end / 1_000_000_000 + " seconds"
    //END REST invocation



    ForechartFlights forechartFlights = new ForechartFlights(jsonResponse)
    //Data Objects
    @ToString(includePackage = false)
    class Forechart {
        boolean wdc
        List<Flight> flightList
        int dayInterval
        int adultCount
        int childCount
        boolean isRescueFare
    }

    @ToString(includePackage = false)
    class Flight {
        String departureStation
        String arrivalStation
        Date date
    }


    //response

    @ToString(includePackage = false)
    class ForechartFlights {
        List<ForechartFlight> outboundFlights
        List<ForechartFlight> returnFlights
    }

    @ToString(includePackage = false)
    class ForechartFlight {
        String departureStation
        String arrivalStation
        String priceType
        String classOfService
        boolean hasMacFlight
        Date date
        Price price;

    }

    @ToString(includePackage = false)
    class Price {
        BigDecimal amount
        String currencyCode
    }

What is reason?

1 Answers1

7

It seems this request takes a good while (8+ seconds) using curl as well:

~> time curl -v -d "@post.data" -H "Content-Type: application/json" https://be.wizzair.com/7.14.0/Api/asset/farechart

*   Trying 104.122.232.212...
* TCP_NODELAY set
* Connected to be.wizzair.com (104.122.232.212) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate: wizzair.com
* Server certificate: DigiCert SHA2 Extended Validation Server CA
* Server certificate: DigiCert High Assurance EV Root CA
> POST /7.14.0/Api/asset/farechart HTTP/1.1
> Host: be.wizzair.com
> User-Agent: curl/7.59.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 407
>
* upload completely sent off: 407 out of 407 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Cache-Control: no-cache,no-store
< Pragma: no-cache
< Expires: -1
< X-XSS-Protection: 1; mode=block
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< Strict-Transport-Security: max-age=31536000
< Server:
< Date: Sun, 27 May 2018 18:07:43 GMT
< Content-Length: 10023
< Connection: keep-alive
< Set-Cookie: ASP.NET_SessionId=hnrxfwuxvkxo34k3zhcljnce; path=/; secure; HttpOnly
< Set-Cookie: _abck=83611DFC82637AC8726723372C6A8EFC50EFF7BD2A040000EFF30A5B01AC6952~-1~Ip07wEKIXzwehsarZ0eh+sBBuiiRDje8DAQpi80fdXk=~-1~-1; expires=Mon, 27 May 2019 18:07:43 GMT; max-age=31536000; path=/; domain=.wizzair.com
< Set-Cookie: bm_sz=41F805925F8BB0BCFE47CBE64B3531A2~QAAQvffvUJsv45ZjAQAAId/IorrnukpLPnmZ8H7WRPTEdCk0rMrrIOdi+wLlRh3DFodvGU9Mu5gq0MDfhTtHxwo4hm0DC2IT5Ql6PrXWlY59p5wf57bBed+P4Lq5+bX7XtlNRFTFda9yjVVzYbgknJ30w8JOrE2prYAGu1mh/9qkFPzvKkJXjGcz7QA8eLUS; Domain=.wizzair.com; Path=/; Expires=Sun, 27 May 2018 22:07:35 GMT; Max-Age=14392; HttpOnly
<
<snip>response data here</snip>
real  0m8.386s
user  0m0.024s
sys 0m0.022s

Where I saved the request data in a file post.data first.

I would suspect that there is some header or other detail in the request that is not identical between the invocations that take a long time (like this curl and the groovy example) and the ones that do not.

If you are using a tool like Postman, check the request headers and see if there is something we are not sending in the ones that take a long time.

update after further testing

I have verified this with postman as well (i.e. fast with postman, slow with java and curl) and no difference in headers. I am fairly convinced this has to do with the handling of https and TLSv1.2.

A potential though perhaps far out culprit might be the reported slow (non-hardware accelerated) AES GCM encryption that TLSv1.2 (which is used by the site as per the above curl trace) allows:

Java Server, TLSv1.1 fast, TLSv1.2 extremely slow (90MByte/sec versus 4MByte/sec)

Slow AES GCM encryption and decryption with Java 8u20

update 2 after some more forensics

by sending in the following flag to groovy (or java) when running the test:

-Djavax.net.debug=all

we can see that the client script receives the encrypted data:

<snip a ton of network and tls detail>
05B0: 9E EA 98 06 6B 91 EC 2A   76 C8 F3 39 81 88 C5 30  ....k..*v..9...0
05C0: 02 34 45 E9 8C 12 EE 07   E3 31 C7 5C 8F DB FD C9  .4E......1.\....
05D0: 80 F4 0A F7 B4 57 CC 68   EF 96 70 7C 5E B6        .....W.h..p.^.
main, READ: TLSv1.2 Application Data, length = 1502
Padded plaintext after DECRYPTION:  len = 1478
0000: 48 54 54 50 2F 31 2E 31   20 32 30 30 20 4F 4B 0D  HTTP/1.1 200 OK.
0010: 0A 43 6F 6E 74 65 6E 74   2D 54 79 70 65 3A 20 61  .Content-Type: a
0020: 70 70 6C 69 63 61 74 69   6F 6E 2F 6A 73 6F 6E 3B  pplication/json;
0030: 20 63 68 61 72 73 65 74   3D 75 74 66 2D 38 0D 0A   charset=utf-8..
00
<snip - HttpOnly is the end of the last response cookie, after that 
I'm assuming the encrypted data starts> 
0410: 3B 20 48 74 74 70 4F 6E   6C 79 0D 0A 0D 0A 1F 8B  ; HttpOnly......
0420: 08 00 00 00 00 00 00 03   CD 98 C1 4A C3 40 14 45  ...........J.@.E
0430: FF 65 D6 09 CC 4C 6D D4   EC A4 E2 AA 45 B0 85 2E  .e...Lm.....E...
<snip - more encrypted data>
0590: 1C 78 6E C4 5E C0 16 39   F0 DC 68 77 99 22 C7 16  .xn.^..9..hw."..
05A0: 39 EC DC B0 45 0E CC 46   BC 2F 60 8B 1C 78 6E C4  9...E..F./`..xn.
05B0: FB 02 B6 C8 81 E7 46 BC   2F 9C 5D E4 4E 6F FC FF  ......F./.].No..
05C0: 20 5E 27 27 00 00                                   ^''..
<THIS IS WHERE WE HANG FOR A LONG TIME>
Duration: 10.904149839 seconds

(well we see a ton of output, but at the end we receive the encrypted data)

and then just hangs there for a long time.

In other words, it is not the receiving of the data or the server taking a long time. We already have the data and then hang.

I'm assuming this is the decryption of the received data taking time and I would attribute it to the above slow decryption or some similar issue with java ssl.

Not rock solid, but seems at least a plausible theory.

Assuming the above theory holds we are still left wondering why curl is slow.

Matias Bjarland
  • 4,124
  • 1
  • 13
  • 21