Posting byte array causes NonRepeatableRequestException

1,575 views
Skip to first unread message

Aukjan

unread,
Oct 21, 2011, 9:03:32 AM10/21/11
to REST assured
I have the following test written (using rest-assured 1.4), testing
our REST service, which stores a datastream:

byte [] bytes = "somestring".getBytes();
given().contentType("application/octet-stream").body(bytes)
.then().expect().statusCode(201)
.when().post("/");

The REST service works as designed (tested using CURL), but with rest-
assured, the REST service is not even reached. The test exists with
the trace below.

Does anyone have a clue why this might be?

Thanks!
- Aukjan


org.apache.http.client.ClientProtocolException
at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:
643)
at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:
576)
at org.apache.http.client.HttpClient$execute.call(Unknown Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:
40)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
116)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
128)
at
com.jayway.restassured.internal.RequestSpecificationImpl.restAssuredDoRequest(RequestSpecificationImpl.groovy:
1019)
at com.jayway.restassured.internal.RequestSpecificationImpl.this
$2$restAssuredDoRequest(RequestSpecificationImpl.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1056)
at
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:
77)
at com.jayway.restassured.internal.RequestSpecificationImpl.this$dist
$invoke$2(RequestSpecificationImpl.groovy)
at com.jayway.restassured.internal.RequestSpecificationImpl
$1.methodMissing(RequestSpecificationImpl.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:597)
at
org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:
90)
at groovy.lang.MetaClassImpl.invokeMissingMethod(MetaClassImpl.java:
811)
at
groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:
1105)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1058)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:884)
at
org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:
66)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:
44)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:
141)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:
153)
at com.jayway.restassured.internal.RequestSpecificationImpl
$1.doRequest(RequestSpecificationImpl.groovy:583)
at groovyx.net.http.HTTPBuilder.post(HTTPBuilder.java:345)
at groovyx.net.http.HTTPBuilder$post.call(Unknown Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:
40)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
116)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
128)
at
com.jayway.restassured.internal.RequestSpecificationImpl.sendRequest(RequestSpecificationImpl.groovy:
649)
at com.jayway.restassured.internal.RequestSpecificationImpl.this
$2$sendRequest(RequestSpecificationImpl.groovy)
at com.jayway.restassured.internal.RequestSpecificationImpl$this
$2$sendRequest.call(Unknown Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:
40)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
116)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
132)
at
com.jayway.restassured.internal.filter.RootFilter.filter(RootFilter.groovy:
28)
at com.jayway.restassured.filter.Filter$filter.call(Unknown Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:
40)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
116)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
132)
at
com.jayway.restassured.internal.filter.FilterContextImpl.next(FilterContextImpl.groovy:
45)
at com.jayway.restassured.filter.FilterContext$next.call(Unknown
Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:
40)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
116)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
128)
at
com.jayway.restassured.internal.RequestSpecificationImpl.invokeFilterChain(RequestSpecificationImpl.groovy:
551)
at com.jayway.restassured.internal.RequestSpecificationImpl
$invokeFilterChain.callCurrent(Unknown Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:
44)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:
141)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:
157)
at
com.jayway.restassured.internal.RequestSpecificationImpl.applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy:
880)
at com.jayway.restassured.internal.RequestSpecificationImpl.this
$2$applyPathParamsAndSendRequest(RequestSpecificationImpl.groovy)
at com.jayway.restassured.internal.RequestSpecificationImpl$this
$2$applyPathParamsAndSendRequest.callCurrent(Unknown Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:
44)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:
141)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:
157)
at
com.jayway.restassured.internal.RequestSpecificationImpl.post(RequestSpecificationImpl.groovy:
122)
at com.jayway.restassured.specification.RequestSender
$post.call(Unknown Source)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:
40)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
116)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:
128)
at
com.jayway.restassured.internal.ResponseSpecificationImpl.post(ResponseSpecificationImpl.groovy:
240)
at
com.mycomp.test.functional.rest.SIFTRestStreamBasics.createStream(SIFTRestStreamBasics.java:
44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:
39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod
$1.runReflectiveCall(FrameworkMethod.java:44)
at
org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:
15)
at
org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:
41)
at
org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:
20)
at
org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:
28)
at org.junit.rules.TestWatchman$1.evaluate(TestWatchman.java:48)
at
org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:
79)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:
71)
at
org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:
49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:
49)
at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:
38)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:
467)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:
683)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:
390)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:
197)
Caused by: org.apache.http.client.NonRepeatableRequestException:
Cannot retry request with a non-repeatable request entity.
at
org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:
474)
at
org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:
641)
... 95 more

Johan Haleby

unread,
Oct 21, 2011, 9:30:20 AM10/21/11
to rest-a...@googlegroups.com
Hi, 

I've tried to reproduce the error but it works for me:

        byte[] bytes = "somestring".getBytes();      
        given().
                contentType("application/octet-stream").
                body(bytes).
        expect().
                statusCode(200).
        when().
                post("/binaryBody");

I've added a test called "requestSpecificationWithContentTypeOctetStreamAllowsSpecifyingBinaryBodyForPost" in JSONPostITest. Have a look at it if you like.. 

If you're byte array is large you should use multi-part form data uploading instead. 

/Johan

Aukjan van Belkum

unread,
Oct 21, 2011, 11:07:22 AM10/21/11
to rest-a...@googlegroups.com
Thanks for the test, and the quick reply ;)

.. so strange .. here it still fails. I will dive more into the HTTP client to see why it is failing (trying a retry?).

Will followup later!

- Aukjan

Aukjan van Belkum

unread,
Oct 25, 2011, 6:52:29 AM10/25/11
to rest-a...@googlegroups.com
Update:

Finally got a chance to do real debugging.. Turned out to be a problem with authorization. This was not implemented
(yet) for this resource, causing some errors. Strange though, that I did not get the 401 back, but got the 'Cannot retry
non-repeatable request' (see below in the trace)

Thanks again for your help....

- Aukjan

DEBUG [org.apache.http.headers] << HTTP/1.1 401 Unauthorized
DEBUG [org.apache.http.headers] << WWW-Authenticate: basic realm="Login"
DEBUG [org.apache.http.headers] << Cache-Control: must-revalidate,no-cache,no-store
DEBUG [org.apache.http.headers] << Content-Type: text/html;charset=ISO-8859-1
DEBUG [org.apache.http.headers] << Content-Length: 1278
DEBUG [org.apache.http.headers] << Server: Jetty(7.3.1.v20110307)
DEBUG [org.apache.http.impl.client.DefaultHttpClient] Connection can be kept alive indefinitely
DEBUG [org.apache.http.impl.client.DefaultHttpClient] Target requested authentication
DEBUG [org.apache.http.impl.client.DefaultTargetAuthenticationHandler] Authentication schemes in the order of
preference: [ntlm, digest, basic]
DEBUG [org.apache.http.impl.client.DefaultTargetAuthenticationHandler] Challenge for ntlm authentication scheme not
available
DEBUG [org.apache.http.impl.client.DefaultTargetAuthenticationHandler] Challenge for digest authentication scheme not
available
DEBUG [org.apache.http.impl.client.DefaultTargetAuthenticationHandler] basic authentication scheme selected
DEBUG [org.apache.http.impl.client.DefaultHttpClient] Authorization challenge processed
DEBUG [org.apache.http.impl.client.DefaultHttpClient] Authentication scope: BASIC 'Login'@localhost:9090
DEBUG [org.apache.http.impl.client.DefaultHttpClient] Found credentials
DEBUG [org.apache.http.wire] << "<html>[\n]"
DEBUG [org.apache.http.wire] << "<head>[\n]"
DEBUG [org.apache.http.wire] << "<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1"/>[\n]"
DEBUG [org.apache.http.wire] << "<title>Error 401 Unauthorized</title>[\n]"
DEBUG [org.apache.http.wire] << "</head>[\n]"
DEBUG [org.apache.http.wire] << "<body>[\n]"
DEBUG [org.apache.http.wire] << "<h2>HTTP ERROR: 401</h2>[\n]"
DEBUG [org.apache.http.wire] << "<p>Problem accessing /file/. Reason:[\n]"
DEBUG [org.apache.http.wire] << "<pre> Unauthorized</pre></p>[\n]"
DEBUG [org.apache.http.wire] << "<hr /><i><small>Powered by Jetty://</small></i>[\n]"
DEBUG [org.apache.http.wire] << "</body>[\n]"
DEBUG [org.apache.http.wire] << "</html>[\n]"
DEBUG [org.apache.http.client.protocol.RequestAddCookies] CookieSpec selected: best-match
DEBUG [org.apache.http.impl.client.DefaultHttpClient] Cannot retry non-repeatable request
DEBUG [org.apache.http.impl.conn.DefaultClientConnection] Connection shut down
DEBUG [org.apache.http.impl.conn.SingleClientConnManager] Releasing connection
org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@6d1e7cc6

On 10/21/11 3:30 PM, Johan Haleby wrote:

> Hi,
>
> I've tried to reproduce the error but it works for me:
>
> byte[] bytes = "somestring".getBytes();
> given().
> contentType("application/octet-stream").
> body(bytes).
> expect().
> statusCode(200).
> when().
> post("/binaryBody");
>
> I've added a test called "requestSpecificationWithContentTypeOctetStreamAllowsSpecifyingBinaryBodyForPost" in
> JSONPostITest

> <https://github.com/jayway/rest-assured/blob/master/examples/rest-assured-itest-java/src/test/java/com/jayway/restassured/itest/java/JSONPostITest.java>.


> Have a look at it if you like..
>
> If you're byte array is large you should use multi-part form data uploading

> <http://code.google.com/p/rest-assured/wiki/Usage#Multi-part_form_data> instead.
>
> /Johan

Johan Haleby

unread,
Oct 25, 2011, 7:17:37 AM10/25/11
to rest-a...@googlegroups.com
Thanks for letting us know. Btw, you can use Rest Assured to for authentication as well.

/Johan

Aukjan van Belkum

unread,
Oct 25, 2011, 8:19:23 AM10/25/11
to rest-a...@googlegroups.com
Oh I do ;) Works like a charm .. But our 'resource' was broken .. (recently introduced security to it), that's what went
wrong (actually on the authentication side).

So much more to fix!

Thanks!

- Aukjan

Johan Haleby

unread,
Oct 25, 2011, 8:23:05 AM10/25/11
to rest-a...@googlegroups.com
Great :) If you have any more questions, suggestions or feedback just let us know.

/Johan

Aukjan van Belkum

unread,
Nov 29, 2011, 6:08:42 AM11/29/11
to rest-a...@googlegroups.com
On 10/25/11 2:23 PM, Johan Haleby wrote:
> Great :) If you have any more questions, suggestions or feedback just let us know.
>
> /Johan
>

Well.. I do ;) So I am back ..

We finally implemented the security on this resource, so I gave the test a whirl.. But still no dice: (see attached log).

I think the problem lies in the fact that it thinks it is a 'non-repeatable' request, and since in this case you have to
repeat the request due to authentication, it can not do this.

Do you have any suggestion on how to circumvent this?

(BTW I tested this service to be working with other tools (firefox + poster extension))

Thanks!
- Aukjan

rest-assured.log

Johan Haleby

unread,
Nov 29, 2011, 2:17:25 PM11/29/11
to rest-a...@googlegroups.com
Hi,

I'm not familiar with the term 'non-repeatable request', what does this
mean? Are you using basic authentication? In that case you may want to
try the preemptive basic authentication
(given().auth().preemptive().basic("username", "password"). ..) and see
if it makes any difference.

Regards,
/Johan

Aukjan van Belkum

unread,
Nov 29, 2011, 2:55:57 PM11/29/11
to rest-a...@googlegroups.com
On 11/29/11 8:17 PM, Johan Haleby wrote:
> Hi,
>
> I'm not familiar with the term 'non-repeatable request', what does this mean?
This means (as you can see in the log) that the HTTP client will only try the request once, which is done for requests
which can't be/are not buffered (such as input streams). For this reason there is an extension to HttpEntityWrapper:
BufferedHttpEntity
(http://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/entity/BufferedHttpEntity.html) (in java),
which provides this buffering and does allow a request to be posted twice. This might be something to change, although I
don't know how to achieve this in the groovy HTTPBuilder. (not familiar with groovy).

> Are you using basic authentication? In that case you may want to try the preemptive basic authentication
> (given().auth().preemptive().basic("username", "password"). ..) and see if it makes any difference.
Yes I am, didn't know about the preemptive solution, but implemented something similar by just setting an Authorization
header ;) .. Now it works as expected. Will look at this 'preemptive' solution though, much cleaner.

But on the 'unbuffered' post... It might be useful to look into this, not only for this instance, but possible future
issues..

Thanks for the pointer!

- Aukjan

Reply all
Reply to author
Forward
0 new messages