Request.Post Method to Web Server using CherryPy - request

I am following the blog: Build your own Python RESTful Web Service to mock a web server using cherrypy.
The server code is
import cherrypy
class MyWebService(object):
#cherrypy.expose
#cherrypy.tools.json_out()
#cherrypy.tools.json_in()
def process(self):
return "hello world!"
if __name__ == '__main__':
config = {'server.socket_host': '0.0.0.0'}
cherrypy.config.update(config)
cherrypy.quickstart(MyWebService())
running above script by python server.py will start a service at http://localhost:8080.
Successful Call
Then we can call the service using post method:
import requests
headers = {'Content-Type': 'application/json'}
response = requests.post('http://localhost:8080/process', headers=headers, json={})
It successfully returns "hello world!" with status= 200.
Failed Call
However, if changing "Content-Type": application/json -> text/plain in headers and json -> data:
headers = {'Content-Type': 'text/plain'}
response = requests.post('http://localhost:8080/process', headers=headers, data={})
It responds the error code 415, and the error message
Traceback (most recent call last):
File "/Users/hshung/opt/anaconda3/lib/python3.9/site-packages/requests/models.py", line 910, in json
return complexjson.loads(self.text, **kwargs)
File "/Users/hshung/opt/anaconda3/lib/python3.9/json/__init__.py", line 346, in loads
return _default_decoder.decode(s)
File "/Users/hshung/opt/anaconda3/lib/python3.9/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/Users/hshung/opt/anaconda3/lib/python3.9/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
.....
I did try the following server code
#cherrypy.tools.json_in(content_type=['application/json', 'text/plain'])
The API call still fails, and the status code is 400.
Can anyone who is familiar with cherryPy and API request help me figure out how to fix it?

The problem is that with:
headers = {'Content-Type': 'text/plain'}
response = requests.post('http://localhost:8080/process', headers=headers, data={})
You're sending a POST request with an empty body, it should work if you specify the data param as a string containing any valid json:
headers = {'Content-Type': 'text/plain'}
response = requests.post('http://localhost:8080/process', headers=headers, data='{}')
For reference take a look a the values that are sent:
>>> requests.post('http://localhost:8080/process', headers=headers, json={})
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): localhost:8080
send: b'POST /process HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: python-requests/2.27.1\r\nAccept-Encoding: gzip, deflate, br\r\nAccept: */*\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nContent-Length: 2\r\n\r\n'
send: b'{}'
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/json
header: Server: CherryPy/18.6.1
header: Date: Fri, 22 Jul 2022 23:16:49 GMT
header: Content-Length: 14
DEBUG:urllib3.connectionpool:http://localhost:8080 "POST /process HTTP/1.1" 200 14
<Response [200]>
>>> requests.post('http://localhost:8080/process', headers=headers, data={})
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): localhost:8080
send: b'POST /process HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: python-requests/2.27.1\r\nAccept-Encoding: gzip, deflate, br\r\nAccept: */*\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nContent-Length: 0\r\n\r\n'
reply: 'HTTP/1.1 400 Bad Request\r\n'
header: Content-Type: text/html;charset=utf-8
header: Server: CherryPy/18.6.1
header: Date: Fri, 22 Jul 2022 23:16:55 GMT
header: Content-Length: 3023
DEBUG:urllib3.connectionpool:http://localhost:8080 "POST /process HTTP/1.1" 400 3023
<Response [400]>
>>> requests.post('http://localhost:8080/process', headers=headers, data='{}')
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): localhost:8080
send: b'POST /process HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: python-requests/2.27.1\r\nAccept-Encoding: gzip, deflate, br\r\nAccept: */*\r\nConnection: keep-alive\r\nContent-Type: text/plain\r\nContent-Length: 2\r\n\r\n'
send: b'{}'
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/json
header: Server: CherryPy/18.6.1
header: Date: Fri, 22 Jul 2022 23:17:00 GMT
header: Content-Length: 14
DEBUG:urllib3.connectionpool:http://localhost:8080 "POST /process HTTP/1.1" 200 14
<Response [200]>
>>>
And you're correct with:
#cherrypy.tools.json_in(content_type=['application/json', 'text/plain'])
That is also required.

Related

Gatling. How to send POST multipart/form-data without file

I try to send POST multipart/form-data but without attached file. It's like the client sends sign up form with email + password and without avatar file(this field isn't required).
HTTP request:
POST https://.../profile/user/own
headers=
Authorization: bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiIwN2NjMDUzYS0wMTczLTExZWItOWI1OC0wMTg4NjFhYmViYjAiLCJzY29wZSI6WyJjbGllbnQiXSwiZXhwIjoxNjAxMzc0MzEzLCJ1dWlkIjoiMDdjYzA1M2EtMDE3My0xMWViLTliNTgtMDE4ODYxYWJlYmIwIiwiYXV0aG9yaXRpZXMiOlsiUGF5bWVudE1hcmtldENsaWVudCIsImxvYmJ5X2NoYXQiLCJVc2VyQmFsYW5jZSIsInVzZXItc2xvdC1yZWFkIiwibGVhdmVfY2FsbCIsInJlYWRfc2NoZWR1bGVfdXNlciIsInVzZXItY2FuY2VsLXNsb3QiLCJyZWFkX3VzZXJfcXVlc3Rpb25uYWlyZSIsIndyaXRlX3RpbWV6b25lIiwicmVhZF90aGVyYXBpc3RzX2luZm8iLCJlbmRfc2Vzc2lvbiIsImpvaW5fY2FsbCIsImVkaXRfdXNlciIsImFuc3dlcl9hY3Rpb24iLCJyZWFkX3Nlc3Npb24iLCJQYXltZW50VmVyaWZpQ2xpZW50IiwiYmVnaW5fc2Vzc2lvbiIsIm9jY3VweS1zbG90Iiwid3JpdGVfbWVzc2FnZSIsInJlYWRfdXNlciIsInJlYWRfY29udmVyc2F0aW9uIiwicmVhZF9jaGF0IiwicmVhZF9jdXJyZW50X2NoYXQiLCJzb2NrZXQiLCJtYWtlX2NhbGwiLCJyZWFkX2NhbGwiLCJyZWFkX21lc3NhZ2UiLCJjYWxsX3Rva2VuIl0sImp0aSI6Ijg1NjQ5MmJhLTI0ODUtNDAyZC1hZTJhLWZiY2E2YjhkNGY2MSIsImNsaWVudF9pZCI6ImNsaWVudCJ9.APWse9P8SIJtDMMay8UTT9CN_JEvSIRaznn8JALcYfxz107IaL5ezwEJfIEDBb9_WEDeVKvpjI1eUmiYBQiOcF5LkIPhpww_8vaSbWvWP3Tkg21QQceNEZwnjucMc6Doj1YNlx3iOs03Mv8zmOJZ2S1acz5sVj5cK_ufrItG7Ic_-bbpW67Byl1vNgbTgaJoGMRAgqfCxKpAVpxMFqNw3F8FMKe0dm-uYmJwpKlWVg4sEUOW7LSZ6wr3c5XgBHXVvTzVFb0sJyhFkw9W1nrMSJTxJqsaVGEzIe01qhQZasbRkMxC32XXlFzpGSmBDJpdWpTD3pUXrIhD4v15PWt3wg
accept: */*
host: api.dev.psychicbook.net
content-type: multipart/form-data
content-length: 108
formBody=
userData: {"email":"automation.tku1fin9av3#test.com","nickname":"5SkHTB0EVs"}
=========================
HTTP response:
status=
500
headers=
Server: nginx/1.17.10
Date: Mon, 28 Sep 2020 10:11:53 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,OPTIONS
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
X-Application-Context: gateway-service:develop:8765
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Strict-Transport-Security: max-age=15724800; includeSubDomains
body=
{"timestamp":1601287913987,"status":500,"error":"Internal Server Error","exception":"org.springframework.web.multipart.MultipartException","message":"Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found","path":"/profile/user/own"}
There is a special method for file uploading -> .formUpload("file", "image.jpg"), but I don't want to send any file.
If I make the same with Insomnia or anoter REST client, everything is OK, and it looks like:
HttpResponse<String> response = Unirest.post("https://.../profile/user/own")
.header("authorization", "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJjMGRlNWI3ZS0wMTYzLTExZWItOWI1OC0wMTg4NjFhYmViYjAiLCJzY29wZSI6WyJjbGllbnQiXSwiZXhwIjoxNjAxMzY3NzUyLCJ1dWlkIjoiYzBkZTViN2UtMDE2My0xMWViLTliNTgtMDE4ODYxYWJlYmIwIiwiYXV0aG9yaXRpZXMiOlsiUGF5bWVudE1hcmtldENsaWVudCIsImxvYmJ5X2NoYXQiLCJVc2VyQmFsYW5jZSIsInVzZXItc2xvdC1yZWFkIiwibGVhdmVfY2FsbCIsInJlYWRfc2NoZWR1bGVfdXNlciIsInVzZXItY2FuY2VsLXNsb3QiLCJyZWFkX3VzZXJfcXVlc3Rpb25uYWlyZSIsIndyaXRlX3RpbWV6b25lIiwicmVhZF90aGVyYXBpc3RzX2luZm8iLCJlbmRfc2Vzc2lvbiIsImpvaW5fY2FsbCIsImVkaXRfdXNlciIsImFuc3dlcl9hY3Rpb24iLCJyZWFkX3Nlc3Npb24iLCJQYXltZW50VmVyaWZpQ2xpZW50IiwiYmVnaW5fc2Vzc2lvbiIsIm9jY3VweS1zbG90Iiwid3JpdGVfbWVzc2FnZSIsInJlYWRfdXNlciIsInJlYWRfY29udmVyc2F0aW9uIiwicmVhZF9jaGF0IiwicmVhZF9jdXJyZW50X2NoYXQiLCJzb2NrZXQiLCJtYWtlX2NhbGwiLCJyZWFkX2NhbGwiLCJyZWFkX21lc3NhZ2UiLCJjYWxsX3Rva2VuIl0sImp0aSI6Ijg5ZDg4OTViLTU1NzQtNDk2OC1hNmJhLWRmZjcyYmIxYWI1MyIsImNsaWVudF9pZCI6ImNsaWVudCJ9.bW7F65elarJNQ9RkfIJcH0uq9Og0ue8TXNZ7Gh_FFCdj_c8SVHlPXwu-nEoZZSTVk3gBB2I_hw8MqPfCZVZrlAlzyIfAcyuQ1WRgRH5-xVzYej3XqBEADuCjBabcO87LoPwz_vYCT3JZVhNZHcDMOkQ429dg0HdKeSBd6qJaPYCgWgq529b9-wnufNBx9LHyaTYLWZC5nMfmDbyep3sc2_q6YzqKMMH5a-s1SmOgQpKbCNyCx7gui3tiYqQh21zMN-PhtkRNAD78awzpIpZhuZTF-AbrQkI6J1Yvsg59AYkZZVBd5gyCSopydquezf7xaAc3Ot2L-DubGzWwr2u9gA")
.header("content-type", "multipart/form-data; boundary=---011000010111000001101001")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"userData\"\r\n\r\n{\"email\":\"automation.tku1fin9av3#test.com\",\"nickname\":\"qatest5\"}\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n\r\n-----011000010111000001101001--\r\n")
.asString();
How can I make the same but with Gatling?
I had the same issue. I have some entries with, and some without files. Both need to be uploaded using body parts.
When i set one fields using StringBodyPart it worked for me:
val uploadDocument = doIfEqualsOrElse(session => session("file").as[String], "") {
// executed if the session value stored in "myKey" starts with "admin"
exec(
http("upload: ${title}")
.post(
clientPortalUrl + "/customerportal/api/documents"
)
.headers(multipartUploadHeaders)
//if we do not call formUpload() we need set one field using StringBodyPart, the rest will follow.
.bodyPart(StringBodyPart("title", "${title}")).asMultipartForm
.formParam("documentType", "${documentType}")
.formParam("accountId", "${accountId}")
.formParam("period", "${period}")
.formParam("endDate", "${endDate}")
.formParam("signer", "${signer}")
.formParam("nexusRecipient", "${nexusRecipient}")
.formParam("vatFiscalEntityDivision", "${vatFiscalEntityDivision}")
.formParam("editor", "${editor}")
.formParam("repeatable", "${repeatable}")
.requestTimeout(5.minutes)
.check(status.is(201))
.check(jsonPath("$.title").exists)
)
} {
exec(
http("upload: ${title}")
.post(
clientPortalUrl + "/customerportal/api/documents"
)
.headers(multipartUploadHeaders)
.formParam("title", "${title}")
.formParam("documentType", "${documentType}")
.formParam("accountId", "${accountId}")
.formParam("period", "${period}")
.formParam("endDate", "${endDate}")
.formParam("signer", "${signer}")
.formParam("nexusRecipient", "${nexusRecipient}")
.formParam("vatFiscalEntityDivision", "${vatFiscalEntityDivision}")
.formParam("editor", "${editor}")
.formParam("repeatable", "${repeatable}")
.formUpload("files[]", "${file}")
.requestTimeout(5.minutes)
.check(status.is(201))
.check(jsonPath("$.title").exists)
)
}

How to resolve entitlement error in ibm watson nlc?

I am trying to train the IBM Watson NLC locally on my computer and after it trains for few mins it shows me this error
{
"code" : 400,
"error" : "Entitlement error",
"description" : "This user or service instance has the maximum number of classifiers."
}
(mytestenv) (base) C:\Users\mohana.kalyan\Desktop\ibm3\nlc-icd10-classifier>curl -i -u "apikey:#####################################" -F training_data=#C:\Users\mohana.kalyan\Desktop\ibm3\nlc-icd10-classifier\data\weather_data_train.csv -F training_metadata="{\"language\":\"en\",\"name\":\"ICD_classifier\"}" "https://gateway-fra.watsonplatform.net/natural-language-classifier/api/v1/classifiers"
HTTP/1.1 100 Continue
X-Note: Gateway Ack
HTTP/1.1 400 Bad Request
X-Backside-Transport: FAIL FAIL
Content-Type: application/json
X-XSS-Protection: 1
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
Cache-Control: no-cache, no-store
Pragma: no-cache
Expires: 0
x-global-transaction-id: 0e7fa6da5c6a722c37a4550d
X-DP-Watson-Tran-ID: gateway-fra-dp02-933516557
X-DP-Transit-ID: gateway-fra-dp02-933516557
Strict-Transport-Security: max-age=31536000;
Content-Length: 141
Date: Mon, 18 Feb 2019 08:51:56 GMT
Connection: close
{
"code" : 400,
"error" : "Entitlement error",
"description" : "This user or service instance has the maximum number of classifiers."
}

AngularJs $http.post() request is not working properly

AngularJs $http.post() request is not working properly
I want to store one task to my db. If amount of data in assignedMember is more than 175 it will not send got 404 error but If amount of data in assignedMember is less than 175 it will send success and store my db. Any idea about this. I dont what wrong with me. Please help me thank you
This is my json data
$scope.task=
{
"title": "My Title",
"description": "My Description",
"assignedMember": [
{
"userId": "51b701dae4b0dd92df2c32d1",
"status": "ASSIGNED"
},
{
"userId": "52de0811e4b04615ce7ed6bd",
"status": "ASSIGNED"
},
{
"userId": "559f8e97e4b0a5cdcd66bb76",
"status": "ASSIGNED"
},
.
.
.
.
.
.etc upto 500 data
]
}
This is my post request api
var responsePromise = $http.post("api/tasks",$scope.task);
responsePromise.success(function(data, status, headers, config) {
alert("Data created successfully");
});
responsePromise.error(function(data, status, headers, config) {
alert("Error")
});
If assigned member size is more than 175 or Content Length in browser is greater than 24580 when i send this json i got 404 error
If assigned member size is less than 175 or Content Length in browser is lesser than 10080 when i send this json it will success
If i getting 404 error my browser console is like this
Request header
-------------
Host: localhost
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: application/json, text/plain, /
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json;charset=utf-8
Referer: http://localhost/login.do
Content-Length: 24580
Response header
--------------
Connection: close
Content-Encoding: gzip
Content-Type: text/html
Date: Thu, 15 Dec 2016 14:21:56 GMT
Server: nginx/1.10.1
Transfer-Encoding: chunked
Is it any restriction in my nginx server? Please help me
Post request have no restriction rit? and get request is limited to 2048KB
Actually I am sending via post so what problem i am facing?
Connection: close, I think your server have not accept large count of data.
nginx "fails fast" when the client informs it that it's going to send a body larger than the client_max_body_size by sending a 413 response and closing the connection.
Most clients don't read responses until the entire request body is sent. Because nginx closes the connection, the client sends data to the closed socket, causing a TCP RST.
If your HTTP client supports it, the best way to handle this is to send an Expect: 100-Continue header. Nginx supports this correctly as of 1.2.7, and will reply with a 413 Request Entity Too Large response rather than 100 Continue if Content-Length exceeds the maximum body size.
Referred from

Angular $http doesn't turn all response headers

I would like to get the 'X-Total-Count' response header of a RESTful API. While trying to get the header in the query callback function of my ngResource 'User', it seems that $http ignores a lot of the reponse headers.
These are the response headers of my request:
Access-Control-Allow-Origin: *
Cache-Control: max-age=0, private, must-revalidate
Connection: close
Content-Encoding: gzip
Content-Type: application/json; charset=utf-8
Date: Fri, 17 Oct 2014 11:13:26 GMT
Link: <http://xxxx.xxx/user?page=2>; rel="next"
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Total-Count: 32
Here I'm querying the set of users:
User.query({
page: $scope.pagingOptions.currentPage,
limit: $scope.pagingOptions.pageSize
}, function(users, responseHeaders) {
console.log(responseHeaders());
console.log(responseHeaders('X-Total-Count'));
});
That's the result of the console:
Object { cache-control="max-age=0, private, must-revalidate", content-type="application/json; charset=utf-8"}
null
So why the $http's responseHeaders() function turns only 2 of 10 header properties?
Are you sure you are not doing cross origin resource sharing?
see 7.1.1 Handling a Response to a Cross-Origin Request
That specification forbids access to any response header field other
except the simple response header fields (i.e. Cache-Control,
Content-Type, ...)

What kinds of things can cause ngSanitize to throw a Parse Error

I have an AngularJS app that parses HTML which largely comes from emails. In some cases data-bind-html will throw a Parse Error but not all cases. I've been unable to determine why.
Does anyone know some types of tokens or syntax that can cause the error?
Here's a sample of a file which trips it up:
,
I received the following error message...:
------------------------------------------------------------------------ The server encountered an unexpected condition that prevented it from
fulfilling the request.
HTTP_Status = 500 (Internal Server Error)
URL =
----------------------------------------- Request Headers
----------------------------------------- POST /ss/servlet/FooServlet/ HTTP/1.1 Accept: Accept: / Host: mydomain.org Content-Length: 141
User-Agent: FooBar/2.1.94 Pragma: no-cache Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded; charset="utf-8"
Connection: Keep-Alive Cookie:
BIGipServerpool_cookie_apps_ss_8188=rd860o00000000000000000000ffff0a0ad0aco8188;
JSESSIONID=5215F941A173B6127E9A95B3E99E3A74
----------------------------------------- Response Headers
----------------------------------------- HTTP/1.1 500 Internal Server Error Server: Apache-Coyote/1.1 Set-Cookie:
JSESSIONID=A9B7C98E5359D961DC8958F87CCCF49E; Path=/ss
Content-Disposition: attachment; filename="spreadsheet.csv"
Content-Description: spreadsheet.csv Content-Transfer-Encoding: binary
Content-Type: application/csv;charset=ISO-8859-1 Transfer-Encoding:
chunked Date: Wed, 06 Mar 2013 18:46:19 GMT Connection: close
-------------...
Emails can contain a lot of arbitrary encoding and invalid HTML, such as <email#domain.com>. To eliminate the Parse Errors I've implemented my own filter which takes effect before it goes through ngSanitize/bind-html.
ng-bind-html="obj.emailContent | sanitizeEmail"
myModule.filter('sanitizeEmail', function() {
return function(input) {
return input.replace(/<[\w-]*\.[\w-]*>/g, '').replace(/<[\w\.\$-]+[\:#].*>/g, '');
};
});

Resources