Restkit loading gzipped json - gzip

I'm using RestKit to load a gzipped JSON with RKRequest:
RKRequest* request = [[RKClient sharedClient] requestWithResourcePath:urlString delegate:self];
[request send];
but I receive a status 406. When using AsiHttpRequest everything works, the response gets unzipped and I can work with the JSON. When I turn off gzip on server the RKRequest works.
What is wrong? I found no way to tell RKRequest, that the response will be zipped. Any ideas?
EDIT:
It is strange. Sometimes I get
Headers: {
Connection = "Keep-Alive";
"Content-Length" = 14;
"Content-Type" = "text/html; charset=UTF-8";
Date = "Fri, 16 Mar 2012 13:44:16 GMT";
"Keep-Alive" = "timeout=2, max=500";
Server = Apache;
"X-Powered-By" = "Servlet/2.5 JSP/2.1";
}
and sometimes I get application/gzip which is handled correct. My problem is why I get "Content-Type" = "text/html; charset=UTF-8"; sometimes.
And the same request opened in Safari results in a gzip-response always.

Can you post what's in your headers using an HTTP Proxy (like Charles)?
You may need to modify your "request headers" in the post call.
Make sure your firewall is able to accept POST calls. This might be an https issue.
EDIT:
You may need to configure your server to always return the response as a GZIP and DEFLATE based on the extension type. This is based on here (http://betterexplained.com/articles/how-to-optimize-your-site-with-gzip-compression/).
Example:
# compress json format in .htaccess (for apache servers):
AddOutputFilterByType DEFLATE application/json
You can find the 'mod_deflate' documentation here (http://httpd.apache.org/docs/2.0/mod/mod_deflate.html)
If you can post the outgoing headers, that would also be useful, as they should include:
Accept-Encoding: gzip, deflate
Similar issues
https://groups.google.com/forum/?fromgroups#!topic/restkit/Xo84PH1l5kM
Weird "406 not acceptable" error
https://serverfault.com/questions/183843/content-length-not-sent-when-gzip-compression-enabled-in-apache
EDIT:
Make sure you also do this:
[[RKClient sharedClient] setValue:#"gzip" forHTTPHeaderField:#"Accept-Encoding"];
or this
[[RKClient sharedClient] setValue:#"gzip, deflate" forHTTPHeaderField:#"Accept-Encoding"];
This should set the value of your header to accept "gzip" for encoding the response. I noticed these github issues:
https://github.com/RestKit/RestKit/pull/540
https://github.com/RestKit/RestKit/issues/511

Related

Content-Type header property value quoting doesn't work with third-party server

Is it correct to quote the boundary property value of Content-Type header?
I have sent an http-request with two files to a third-party server and get the following response:
Boundary '--"38b14895-fd44-4acc-8287-9f0378691da2"' not found in message body
because RestSharp quotes the boundary value, but the server doesn't unquote it. I can neither change the third-party server nor customize RestSharp header quoting.
What is the problem? Does the http spec allow escaped strings in header property values? I've read the spec, but haven't found a place where this would be explicitly defined.
I create the RestRequest something like this:
private RestRequest CreateRequest( ... )
{
var request_url = $"url?param=value";
var request = new RestRequest( request_url, Method.Post );
request.AddFile( "file1", ..., "file1", "application/xml" );
request.AddFile( "file2", ..., "file2", "audio/x-wav" );
request.AddHeader( "Content-Type", "multipart/form-data" );
return request;
}
and get the following HTTP-request:
POST /url?param=value
Host: 192.168.1.1:80
Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
User-Agent: RestSharp/108.0.1.0
Accept-Encoding: gzip, deflate, br
Content-Type: multipart/form-data; boundary="38b14895-fd44-4acc-8287-9f0378691da2"
Content-Length: 227841
--38b14895-fd44-4acc-8287-9f0378691da2
Content-Type: application/xml
Content-Disposition: form-data; name="file1"; filename="file1"
[data]
--38b14895-fd44-4acc-8287-9f0378691da2
Content-Type: audio/x-wav
Content-Disposition: form-data; name="file2"; filename="file2"
[data]
--38b14895-fd44-4acc-8287-9f0378691da2--
Okay so I have just been dealing with a very similar issue. I found this GitHub Issue which gives some good context into the actual issue that is occurring here but I have also found a fix.
Firstly, you shouldn't manually add the "Content-Type" header. RestSharp will do this for you since you are using the AddFile() method.
I am assuming you are using the latest version of RestSharp, if so you can set the request.OnBeforeRequest property of the RestRequest to handle this and strip out the double quotes around the boundary before the request is sent:
request.OnBeforeRequest = (http) =>
{
var boundary = http.Content.Headers.ContentType.Parameters.First(o => o.Name == "boundary");
boundary.Value = boundary.Value.Replace("\"", String.Empty);
return default;
};
Hope this helps!

Creating multipart/mixed request

I have a very specific case I'm trying to test with Karate.
PUT https://test-api.com/endpoint
Content-Type: multipart/mixed; boundary=BOUNDARY
--BOUNDARY
Content-Type: application/vnd.api+json
{"type": "json-api-object"}
--BOUNDARY
Content-Disposition: attachment; name="fieldname"; filename="filename.jpg"
Content-Type: image/jpeg
Content-Encoding: base64
<binary data>
--BOUNDARY--
Examples show multipart/mixed requests, but they don't show how to set the content-type header on each part. I tried using And multipart header... but that didn't parse correctly.
https://github.com/intuit/karate/blob/master/karate-demo/src/test/java/demo/upload/upload.feature
If I can get this figured out with your help, I'll make a PR against the examples to hopefully help someone in the future.
Yeah this is the first time I'm seeing a need for a custom content-type for each part. This will need a change in the code, so yes an example will expedite a fix.
Meanwhile you can customize the content-type for normal requests.
I had success using mulipart files
* configure headers = {"Content-Type": 'multipart/mixed'}
* configure charset = null
* def mFiles = {}
* set mFiles.jsondata = { value: {'type': 'json-api-object'}, contentType: 'application/vnd.api+json' }
* set mFiles.fieldname = { read: 'classpath:path/to/somePhoto.jpg', filename: 'filename.jpg', contentType: 'image/jpeg' }
Given url "https://my-api.com/put"
And multipart files mFiles
When method PUT
According to this comment, multipart file is preferred for anything other than a string in a multipart field.

How to set Content-Type header in a http get response using C#'s HttpClient?

I am having problems in retrieving the contents of a http get request in the proper charset.
I tried several pieces of code, such as the following:
HttpClient h = new HttpClient();
//Content-Type: text/html; charset=UTF-8
//p.s. contents are in hebrew.
var resp = h.GetAsync("http://www.wnf.co.il");
var content = resp.Result.Content;
//remove the default Content-Type header
content.Headers.Remove("Content-Type");
content.Headers.Add("Content-Type", "text/html; charset=utf-8");
var res = content.ReadAsStringAsync();
var s = res.Result;
Console.WriteLine(s);
which still does not help, I still get the content in wrong encoding.
This post clarifies that setting the header's request headers charset will not help, it's the response's one that needs to be set. (Besides, you will get an error in trying to add
header "Content-Type" to a request Header.)
But I still could not end up with working retrieval of the content in the proper charset (utf-8).
What am I missing ?
I have been doing similar stuff with hebrew sites for a while, in comparing the response's header in Fiddler from this site and others where I do not have this problem - the only difference I see is indeed this Content-Type header in the response.
The issue is probably due to this bug:
https://connect.microsoft.com/VisualStudio/feedback/details/790174/system-net-http-httpcontent-readasstringasync-does-not-handle-imperfect-content-type-headers
The work-around is to get the response as a byte array and encode it yourself:
var bytes = await content.ReadAsByteArrayAsync();
var s = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
As a side-note, is there a reason you're using .Result instead of await? You are blocking the current thread unnecessarily and setting yourself up for deadlocks.

AFNetworking - occasionally get "unacceptable content type: application/json" on http response

I can't figure out why this message is being thrown by AFNetworking 2.0. My understanding is that application/json is the default serialization scheme, so if the server returns JSON with content-type:application/json, why would AFNetworking throw this error?
Failure with messages Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: application/json" UserInfo=0x17e2ed60 {com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x17e84100> { URL: http://XXX/XXX/XXX } { status code: 200, headers {
Connection = "keep-alive";
"Content-Type" = "application/json;charset=UTF-8";
Date = "Fri, 14 Aug 2015 16:16:52 GMT";
Server = "Apache-Coyote/1.1";
"Transfer-Encoding" = Identity;
"X-Application-Context" = application;
} }, NSErrorFailingURLKey=http://XXX/XXX/XXX, NSLocalizedDescription=Request failed: unacceptable content-type: application/json, com.alamofire.serialization.response.error.data=<7b227374 61747573 223a3230 302c2263 6f646522 3a225636 594d227d>}
Commented out URL's with X's in the code block. This only happens sometimes, and it causes the request to fail. If I issue another request, it succeeds.
I'm using an AFHTTPSessionManager singleton to issue all requests.
Try this:
sessionManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript", #"text/html", nil];

AFHttpSessionManager - Multipart POST causing org.codehaus.jackson.JsonParseException

Am trying to use AFNetworking 2's AFHTTPSessionManager to post pdf content to my web service. I have subclassed AFHTTPSessionManager and set request and response serializers to the corresponding AFJsonXXXSerializer. However when I POST the form data as a multi part request, I get a JsonParseException. Am pretty sure this is a straight forward use case and I might be missing something. Pls help, Thanks in advance !
[accessMgr postDataToURL:#"objects-d2" usingParams:nil fileData:imageData andDelegate:self];
which calls the below method to POST
-(void) postDataToURL:(NSString *) urlString usingParams:(id)parameters fileData: (NSData *)fileData andDelegate:(id<RemoteAccessDelegate>) remoteDelegate
{
//RESTSessionManager extends AFHTTPSessionMaanger
RESTSessionManager *manager = [self getManager:remoteDelegate];
[manager POST:urlString parameters: parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:fileData name:#"content" fileName:#"test.pdf" mimeType:#"application/pdf"];
The request goes with the following headers and the form data
POST /d2fs/repositories/ls67sp2/objects-d2 HTTP/1.1
Host: localhost:8080
Content-Type: multipart/form-data; boundary=Boundary+422AF86226B68040
Connection: keep-alive
Transfer-Encoding: Chunked
Accept: application/json
User-Agent: IIG Mobile/1.1 (iPad Simulator; iOS 7.1; Scale/2.00)
Accept-Language: en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5
Authorization: Basic bHNhZG1pbjpsc2FkbWlu
Accept-Encoding: gzip, deflate
--Boundary+422AF86226B68040
Content-Disposition: form-data; name="content"; filename="test.pdf"
Content-Type: application/pdf
%PDF-1.3
%ƒÂÚÂÎßÛ†–ƒ∆
<more file content>
I have verified that the trailing boundary is also set. The response am getting from my web service is
{
"status": 400,
"code": "E_INPUT_ILLEGAL_ARGUMENTS",
"message": "There are illegal arguments provided.",
"details": "org.codehaus.jackson.JsonParseException: Unexpected character ('%' (code 37)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')\n at [Source: org.apache.commons.fileupload.MultipartStream$ItemInputStream#22a5cdce; line: 1, column: 2];Unexpected character ('%' (code 37)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')\n at [Source: org.apache.commons.fileupload.MultipartStream$ItemInputStream#22a5cdce; line: 1, column: 2]"
}
I was able to resolve this issue today. I had to append a json object which was metadata about the object before appending the file data and the upload worked as a charm ! Thanks.
[formData appendPartWithFormData:data name:#"object"];
[formData appendPartWithFileData:fileData name:#"content" fileName:#"test.pdf" mimeType:#"application/pdf"];