cherrypy (python httpserver), how to post xml file in body - post

I want cherrypy to return a xml file in response body in post.
In POST(self), I read a xml file and modify some of the attributes and do these things:
cherrypy.response.headers['Content-Type'] = 'application/soap+xml;charset=UTF-8'
cherrypy.response.headers['Content-Length'] = len(data)
cherrypy.response.body = data
cherrypy.log("response body is: %s" % cherrypy.response.body)
When the client calls, it won't get the body.
curl waits for few seconds and returns this:
curl: (18) transfer closed with 4018 bytes remaining to read
Not sure if I am doing the right thing to send the data back to the client.
I took wireshark trace and I am not seeing any data getting sent out from the server.
Can someone please suggest?

I think I have made this work. Earlier I was calling another function to set above mentioned values. Once I moved them in POST function, things started working. I am not sure what difference do it make. Now, I am setting them this way:
cherrypy.response.headers['Content-Type'] = 'application/soap+xml;charset=UTF-8'
cherrypy.response.headers['Content-Length'] = len(data)
return data

Related

How can I force close excon connection when using chunked request

I am trying to read the first chunk of each image I am requesting to get its mime type and size which I'm able to do.
However, when I use Connection#reset it doesn't kill the connection and keeps downloading next chunks.
I am just wondering is it possible to close the connection after getting the first chunk?
This is my code right now
streamer = lambda do |chunk, _remaining_bytes, total_bytes|
image_format = MimeMagic.by_magic(chunk)
# other code
#connection.reset
end
Excon.defaults[:chunk_size] = 25
#connection = Excon.new(image_url)
#connection.get(response_block: streamer)
I don't believe there is a way currently to stop before the chunked response concludes. That being said, it might be possible that you could get the data you want from a head request and avoid the need for a get request?

Graph call to change planner task returning 204 (and not making the change)

I'm using python to make calls to the Graph API regarding planner and tasks. whenever I use PATCH to try and update the task I get a 204 response back and the task remains unchanged. According to Microsoft's documentation here, this request should always return either a 200, or a 400 level error.
I have tried changing the data that I send to the server, to change the title rather than the dates, however I get the same 204 response no matter what data I send or what field I attempt to change. I have no problem making other graph calls like updating files in One Drive or getting data about a user
def SetDates(task):
'''Update planner to match the start date and due date of the passed in task'''
tid = task["id"]
start = task["startDateTime"]
end = task["dueDateTime"]
newDates = {"dueDateTime": end,"startDateTime": start}
etag = task["#odata.etag"]
session.headers.update({'If-Match':etag})
response = session.patch(f"https://graph.microsoft.com/v1.0/planner/tasks/{tid}", data = newDates)
session.headers.pop('If-Match')
print(task["title"] + " Has been scheduled")
Based on the documentation I expect this to return a status code of 200, and for the response to contain the data of the task that was updated, and for the change to actually be applied to the task.
By default, PATCH requests return an empty response with 204 return code. To get the data updated data back, you should send "Prefer" HTTP header with value "return=representation".
PATCH https://graph.microsoft.com/v1.0/planner/tasks/{task-id}
Content-type: application/json
Content-length: 247
If-Match: W/"JzEtVGFzayAgQEBAQEBAQEBAQEBAQEBAWCc="
Prefer: return=representation
I have finally figured this out.
#Tarken Sevilmis mentioned that in order to get a 200 response from a PATCH request you need to add
Prefer: return=representation
to your request. In my case the reason that my changes weren't being applied was because I hadn't set the content type in the header. The Graph API didn't give an error, but this seems to have been the cause of the issue. Once I set the content type to application/json it gave a proper error indication that the values I gave in the body weren't being read correctly, and I realized that I forgot to parse them to JSON.
Once you set the content headers appropriately and make sure to convert your data to proper JSON everything should work as intended

Occasionally incomplete response from HTTP request

I'm downloading quite big JSON data with luasocket (request), but sometimes, data are incomplete. There is no pattern, if X runs, I have Y fails and Z successful downloads. My downloading code looks like this:
local response = {}
local one, code, headers, status = https.request {
url = url,
sink = ltn12.sink.table(response)
}
And btw, everytime it fails on character 3615. Where is the problem and how to fix it? Is it issue in my code, luasocket, or server?

Gzip decompress JSON POST body in Rails/Passenger/Nginx

We have a function in our Rails code that accepts a JSON POST body:
contacts = ActiveSupport::JSON.decode(request.raw_post.gsub("+", ""))
(I'm aware that I can get this from params["_json"] as well, but we have extremely large (MBs) POST bodies that do not get put into params["_json"] for some reason (and + throws errors too).
Since the JSON is usually sent from a mobile client, it's important to us to optimize the upload size. We want to switch to having the POST body gzipped.
However, no matter what we do, we get the same error with no line number:
MultiJson::DecodeError (743: unexpected token at ''):
We have tried:
gzipped_contacts = Zlib::GzipReader.new(StringIO.new(request.raw_post)).read
contacts = ActiveSupport::JSON.decode(gzipped_contacts.gsub("+", ""))
This:
gzipped_contacts = ActiveSupport::Gzip.decompress(request.raw_post)
contacts = ActiveSupport::JSON.decode(gzipped_contacts.gsub("+", ""))
And the solution found here: Rails: how to unzip a compressed xml request body?
I'm pretty sure this is not occurring at the controller level because I can't log anything there, so it needs to be done in the middleware or at the server (but I can't find anything for Nginx that lets us deflate). Please assist!
Ok, turns out the iPhone client was sending the wrong headers. So the solution for anyone encountering this is to see the advice here:
Rails: how to unzip a compressed xml request body?
And verify that you are sending Content-Type: gzip/json.

Supporting the "Expect: 100-continue" header with ASP.NET MVC

I'm implementing a REST API using ASP.NET MVC, and a little stumbling block has come up in the form of the Expect: 100-continue request header for requests with a post body.
RFC 2616 states that:
Upon receiving a request which
includes an Expect request-header
field with the "100-continue" expectation, an origin server MUST
either respond with 100 (Continue) status and continue to read
from the input stream, or respond with a final status code. The
origin server MUST NOT wait for the request body before sending
the 100 (Continue) response. If it responds with a final status
code, it MAY close the transport connection or it MAY continue
to read and discard the rest of the request. It MUST NOT
perform the requested method if it returns a final status code.
This sounds to me like I need to make two responses to the request, i.e. it needs to immediately send a HTTP 100 Continue response, and then continue reading from the original request stream (i.e. HttpContext.Request.InputStream) without ending the request, and then finally sending the resultant status code (for the sake of argument, lets say it's a 204 No Content result).
So, questions are:
Am I reading the specification right, that I need to make two responses to a request?
How can this be done in ASP.NET MVC?
w.r.t. (2) I have tried using the following code before proceeding to read the input stream...
HttpContext.Response.StatusCode = 100;
HttpContext.Response.Flush();
HttpContext.Response.Clear();
...but when I try to set the final 204 status code I get the error:
System.Web.HttpException: Server cannot set status after HTTP headers have been sent.
The .NET framework by default always sends the expect: 100-continue header for every HTTP 1.1 post. This behavior can be programmatically controlled per request via the System.Net.ServicePoint.Expect100Continue property like so:
HttpWebRequest httpReq = GetHttpWebRequestForPost();
httpReq.ServicePoint.Expect100Continue = false;
It can also be globally controlled programmatically:
System.Net.ServicePointManager.Expect100Continue = false;
...or globally through configuration:
<system.net>
<settings>
<servicePointManager expect100Continue="false"/>
</settings>
</system.net>
Thank you Lance Olson and Phil Haack for this info.
100-continue should be handled by IIS. Is there a reason why you want to do this explicitly?
IIS handles the 100.
That said, no it's not two responses. In HTTP, when the Expect: 100-continue comes in as part of the message headers, the client should be waiting until it receives the response before sending the content.
Because of the way asp.net is architected, you have little control over the output stream. Any data that gets written to the stream is automatically put in a 200 response with chunked encoding whenever you flush, be it that you're in buffered mode or not.
Sadly all this stuff is hidden away in internal methods all over the place, and the result is that if you rely on asp.net, as does MVC, you're pretty much unable to bypass it.
Wait till you try and access the input stream in a non-buffered way. A whole load of pain.
Seb

Resources