How to "dump" request body? - okhttp

Is there any way to get request in the raw representation? I need something like this:
POST /user HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 0
Content-Type: application/json
Host: localhost:8080
User-Agent: okhttp/4.9.0

Try the built in logging interceptor or write your own.
Or try Chucker if you're on Android.

I ended up with a following strange solution in my interceptor:
val buffer = okio.Buffer()
request.body?.writeTo(buffer)
val rawRequest = buildString {
append("${request.method} ${chain.request().url.encodedPath} ${chain.connection()?.protocol().toString().toUpperCase()}\n")
append(chain.request().headers.map { "${it.first}: ${it.second}\n" }.reduce { acc, s -> "$acc$s" })
append(buffer.readString(Charsets.UTF_8))
}
Log.e("RAW request", "$rawRequest")
One important thing: You have to use networkInterceptor

Related

How to uplaod a file to a multipart post request in ruby

I am trying to upload a file(huge) to a multipart post request in ruby. I use the following code but it gives me 500 internal server error:
RestClient.post("urladdress',
:name_of_file_param => File.new('path_of_the_file_to_be_uploaded'))
Following is the multipart request from the endpoint I am using currently:
POST address HTTP/1.1
Host: ip address
Content-Length: 325
Cache-Control: max-age=0
Origin: http://address
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryol2BpbpZ9cZlqFyb
User-Agent: blah blah blah
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://address
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
------WebKitFormBoundaryol2BpbpZ9cZlqFyb
Content-Disposition: form-data; name="uploadedFile"; filename="blah.csv"
Content-Type: text/csv
123456789010290
123456789010290
------WebKitFormBoundaryol2BpbpZ9cZlqFyb
Content-Disposition: form-data; name="submit"
Upload APK
------WebKitFormBoundaryol2BpbpZ9cZlqFyb--
Also if someone can help me with creating a new endpoint which can be used to upload the file without using multipart that is fine too.
Thanks,
RV

WebApi HttpPost not working with parameters

I have a Web Api project with this route config
var config = GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute(
"DefaultApiRoute",
"api/v1/{controller}/{action}");
I have two post method
[HttpPost]
public IHttpActionResult RetrieveTestNoParam()
{
return new JsonResult<string>("This is a test", new JsonSerializerSettings(), Encoding.UTF8, this);
}
[HttpPost]
public IHttpActionResult RetrieveTest(string input)
{
return new JsonResult<string>(input, new JsonSerializerSettings(), Encoding.UTF8, this);
}
The first one is working but the second one gives this respone
{
"Message": "No HTTP resource was found that matches the request URI 'http://test.dev.local/api/v1/NewsApi/RetrieveTest'.",
"MessageDetail": "No action was found on the controller 'NewsApiController' that matches the request."
}
This is what I see in fiddler
POST http://test.dev.local/api/v1/NewsApi/RetrieveTest HTTP/1.1
Host: test.dev.local
Connection: keep-alive
Content-Length: 261
Cache-Control: no-cache
Origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
Content-Type: application/javascript
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
Postman-Token: c2ba631b-4bfd-9379-bf40-0ca1a6a8a3bc
Accept: */*
DNT: 1
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8,nl;q=0.6
Cookie: ASP.NET_SessionId=4kgfwd2u3pwusfdvdsrkt2vt; SC_ANALYTICS_GLOBAL_COOKIE=ddd9185a3e8940c9823e81b7d38cdf20|False; sc_expview=0
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa
Content-Disposition: form-data; name="input"
Dit is de input
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa
Content-Disposition: form-data; name="czczcsdcsdf"
sdfsfsdfsdff
------WebKitFormBoundaryxdYhzJ7A8WnI8qaa--
Any ideas?
Other questions I have about Web Api:
Can a controller contain multiple get or post methods?
Do I need the actionname attribute and what does this attribute do?
Regards
Danny

Issues calling saveChanges with Breezjs

I'm trying to get breeze to work with my webapi/odata service against an Entity framework model with a sql backend.
I've got it to retrieve data from my database, bit am having trouble when I do a createEntity() and then call saveChanges().
I've configured my batch route like this
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
// Web API routes
config.Routes.MapHttpBatchRoute(
routeName: "WebApiBatch",
routeTemplate: "odata/$batch",
batchHandler: new System.Web.Http.Batch.DefaultHttpBatchHandler(GlobalConfiguration.DefaultServer));
When I call save changes I get an http 500 server error, with the message:
Invalid 'HttpContent' instance provided. It does not have a content type header with a value of 'application/http; msgtype=request'.
Parameter name: content
the stream sent to the server is :
POST http://gx9020-01:91/odata/$batch HTTP/1.1
Accept: multipart/mixed
DataServiceVersion: 2.0
Content-Type: multipart/mixed;boundary=batch_9245-db9a-4873
MaxDataServiceVersion: 3.0
Referer: http://localhost:61678/WebForm1.aspx
Accept-Language: en-US
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Connection: Keep-Alive
Content-Length: 731
DNT: 1
Host: gx9020-01:91
Pragma: no-cache
--batch_9245-db9a-4873
Content-Type: multipart/mixed; boundary=changeset_0952-3d90-c3e2
--changeset_0952-3d90-c3e2
Content-Type: application/http
Content-Transfer-Encoding: binary
POST odata/MAP_Counterparty HTTP/1.1
Content-ID: 1
DataServiceVersion: 2.0
Accept: application/atomsvc+xml;q=0.8, application/json;odata=fullmetadata;q=0.7, application/json;q=0.5, */*;q=0.1
Content-Type: application/json
MaxDataServiceVersion: 3.0
{"MAP_CounterpartyID":-1,"SOURCE_SYSTEM":null,"TARGET_SYSTEM":null,"SOURCE_CODE":null,"TARGET_CODE":null,"TARGET_CODE2":null,"DRT_ID":null,"CREATE_DATETIME":null,"MODIFY_DATETIME":null,"Create_User":null,"Modify_User":null}
--changeset_0952-3d90-c3e2--
--batch_9245-db9a-4873--
How can I get the saveChanges() working?
I found the problem. I was using DefaultHttpBatchHandler instead of DefaultODataBatchHandler.

Spring MVC using #RequestParam with RequestMethod.DELETE on Tomcat 6.0.35

I have a simple method (running on Tomcat 6.0.35) that looks like so:
#RequestMapping(value = "/bla/d", method = RequestMethod.DELETE)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void d(#RequestParam String d){
//logic here
}
When I send a DELETE request with post like parameters (d=gggg in the body) I get a 400 Bad Request.
But if I change it to
#RequestMapping(value = "/bla/d", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void d(#RequestParam String d){
//logic here
}
It works perfectly.
I was using a Firefox Add-on to test it (and python and Spring's RestTemplate with same result) here's how the request look with POST(a is a cope pasted method named a with parameter a):
POST /bla/a HTTP/1.1
Host: ~~~~:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 7
Pragma: no-cache
Cache-Control: no-cache
a=asdas
HTTP/1.1 204 No Content
Server: Apache-Coyote/1.1
Date: Tue, 12 Jun 2012 09:29:46 GMT
And delete looks like:
DELETE /bla/d HTTP/1.1
Host: ~~~~~:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 7
d=asdas
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 971
Date: Tue, 12 Jun 2012 09:30:04 GMT
Connection: close
Please help me, I might be missing something stupid but I just can't see it.
My original problem was sending an array via post-like body with DELETE request but it seems that something more basic is wrong.
Well after doing some research and debugging I've found out that Spring's ServletWebREquest calls getParameterValues of org.apache.catalina.connector.RequestFacade.getParameterValues which calls getParameterValues in which I've found the following line (Request.java 2599-2600):
if (!getMethod().equalsIgnoreCase("POST"))
return;
Which kills any attempt to send POST-like parameters with DELETE which means Tomcat is actively restricts this use-case even though the RFC does not restrict such usage(although it does say that some existing implementations may reject such requests, Tomcat just throws it's parameters away).
What brings one that's using Spring and Tomcat and trying to send a DELETE requests with parameters to ugly solutions like getting all the request body with #RequestBody and extracting it manually which makes your supposedly innocent method that just wants to delete something aware of some a Map that contains the request body.
#fmucar
I was having a similar issue and the resolution that I found was to add the fields in the query string. I would still like to know the reasons why a form body would be excluded in this way, but for now this is a work-around.
So for your example it would mean adding
?a=asdas
to the Host: ~~~~~:8080 URL.
I am using spring-webmvc:3.2.4.RELEASE so I'm not sure if this will work in your version or not.
This is a pretty old post, but in case anyone else is looking for how to enable #RequestParam on DELETE methods, here's what I did on tomcat 8.5.4.
#Value("${server.parseBodyMethods}")
private String parseBodyMethods;
#Bean
public TomcatEmbeddedServletContainerFactory containerFactory() {
return new TomcatEmbeddedServletContainerFactory() {
protected void customizeConnector(Connector connector) {
super.customizeConnector(connector);
connector.setParseBodyMethods(parseBodyMethods);
}
};
}
Plug in 'POST,DELETE' to that customizer, and your delete request parameters should start working.
I found parseBodyMethods in org.apache.catalina.connector.Connector, and here is Tomcat's documentation on it:
This is useful in RESTful applications that want to support POST-style semantics for PUT requests. Note that any setting other than POST causes Tomcat to behave in a way that goes against the intent of the servlet specification. The HTTP method TRACE is specifically forbidden here in accordance with the HTTP specification. The default is POST (Source)

How to make Flask/ keep Ajax HTTP connection alive?

I have a jQuery Ajax call, like so:
$("#tags").keyup(function(event) {
$.ajax({url: "/terms",
type: "POST",
contentType: "application/json",
data: JSON.stringify({"prefix": $("#tags").val() }),
dataType: "json",
success: function(response) { display_terms(response.terms); },
});
I have a Flask method like so:
#app.route("/terms", methods=["POST"])
def terms_by_prefix():
req = flask.request.json
tlist = terms.find_by_prefix(req["prefix"])
return flask.jsonify({'terms': tlist})
tcpdump shows the HTTP dialog:
POST /terms HTTP/1.1
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/json; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://127.0.0.1:5000/
Content-Length: 27
Pragma: no-cache
Cache-Control: no-cache
{"prefix":"foo"}
However, Flask replies without keep-alive.
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 445
Server: Werkzeug/0.8.3 Python/2.7.2+
Date: Wed, 09 May 2012 17:55:04 GMT
{"terms": [...]}
Is it really the case that keep-alive is not implemented?
The default request_handler is WSGIRequestHandler.
Before app.run(), Add one line,
WSGIRequestHandler.protocol_version = "HTTP/1.1"
Don't forget from werkzeug.serving import WSGIRequestHandler.
Werkzeug's integrated web server builds on BaseHTTPServer from Python's standard library. BaseHTTPServer seems to support Keep-Alives if you set its HTTP protocol version to 1.1.
Werkzeug doesn't do it but if you're ready to hack into the machinery that Flask uses to instantiate Werkzeug's BaseWSGIServer, you can do it yourself. See Flask.run() which calls werkzeug.serving.run_simple(). What you have to do boils down to BaseWSGIServer.protocol_version = "HTTP/1.1".
I haven't tested the solution. I suppose you do know that Flask's web server ought to be used for development only.

Resources