Apache Jmeter : Post an object not working with ModelAttribute - java

I am working on stress testing our webapplication written in Spring-MVC.
I would like to send an object Person to the application. I have added a system out to get the email, but whenever I am sending the object, it is null. What am I doing wrong?
Server code :
#RequestMapping(value = "/person/add", method = RequestMethod.POST)
public String addPerson(#ModelAttribute("person") Person person, BindingResult bindingResult) {
try {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(person);
System.out.println("String is "+json);
}catch (Exception e){
e.printStackTrace();
}
System.out.println("Person add called"+person.getUsername());
person.setUsername(this.stripHTML(person.getUsername()));
int personId = this.personService.addPerson(person);
if (!(personId == 0)) {
Person person1 = this.personService.getPersonById(personId);
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication authentication = new UsernamePasswordAuthenticationToken(person1, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
return "redirect:/canvaslisting";
} else {
return "redirect:/";
}
}
Object sent in body data :
{"person":{"id":0,"username":"testemail#gmail.com","firstName":"test","cleanCacheFlag":false,"googleDrive":false,"dropbox":false,"evernoteConsumed":false,"statusChangeTimeStamp":null,"useCalendar":false,"newsletterFlag":false,"tourSteps":null,"profession":null,"notiz":null,"telePhone":null,"lastVisitedBoards":null,"leftGroup":null,"optionalEmail":null,"facebookLink":null,"xingLink":null,"linkedinLink":null,"lastOnlineTimestamp":null,"userRole":null,"homePage":null,"excelImportQuota":0,"toEmail":null,"code":null,"authorities":null,"role":null,"newpassword":null,"token":null,"profilePhotoString":null,"accountNonExpired":true,"credentialsNonExpired":true,"accountNonLocked":true,"active":true,"enabled":false}
}
Output :
Person add callednull
Screenshot :
Sample result
Thread Name: Thread Group 2-5
Sample Start: 2017-06-29 15:17:11 IST
Load time: 6
Connect Time: 0
Latency: 6
Size in bytes: 237
Sent bytes:0
Headers size in bytes: 205
Body size in bytes: 32
Sample Count: 1
Error Count: 1
Data type ("text"|"bin"|""): text
Response code: 415
Response message: Unsupported Media Type
Response headers:
HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 1048
Date: Thu, 29 Jun 2017 09:47:11 GMT
Connection: close
HTTPSampleResult fields:
ContentType: text/html;charset=utf-8
DataEncoding: utf-8
Request:
POST http://127.0.0.1:8080/person/add/
POST data:
{"person":{"id":0,"username":"testemail#gmail.com","firstName":"test","cleanCacheFlag":false,"googleDrive":false,"dropbox":false,"evernoteConsumed":false,"statusChangeTimeStamp":null,"useCalendar":false,"newsletterFlag":false,"tourSteps":null,"profession":null,"notiz":null,"telePhone":null,"lastVisitedBoards":null,"leftGroup":null,"optionalEmail":null,"facebookLink":null,"xingLink":null,"linkedinLink":null,"lastOnlineTimestamp":null,"userRole":null,"homePage":null,"excelImportQuota":0,"toEmail":null,"code":null,"authorities":null,"role":null,"newpassword":null,"token":null,"profilePhotoString":null,"accountNonExpired":true,"credentialsNonExpired":true,"accountNonLocked":true,"active":true,"enabled":false}
}
[no cookies]
Request Headers:
Connection: close
Content-Length: 717
Content-Type: application/x-www-form-urlencoded

Change header Content-Type in HTTP Header Manager from:
Content-Type: application/x-www-form-urlencoded
To:
Content-Type: application/json

Shouldn't you just have an #RequestBody annotation on person ?
public String addPerson(#RequestBody Person person);

Well, there is a typo or copy-paste issue in your JMeter request
Also your JMeter configuration might be missing HTTP Header Manager configured to send Content-Type header with the value of application/json

Related

Bitstamp API: Always receiving API0000 (Missing key, signature and nonce parameters.)

Studying this SO question ( Authenticated Java Jersey REST call to Bitstamp ), I see that OP had a similar issue. Unfortunately, I can't make the call work in my own implementation: I tried sending key, nonce and signature both via query-parameters as well as json formatted in the request's body. I logged headers and content, so in those two cases, these are the resulting logs:
// send in body
---> POST https://www.bitstamp.net/api/v2/balance/ HTTP/1.1
Accept: application/json;charset=UTF-8
Content-Type: application/json;charset=UTF-8
Content-Length: 140
{"key":"12345678901234567890123456789012","nonce":1234567890,"signature":"1234567890123456789012345678901234567890123456789012345678901234"}
---> END HTTP (140-byte body)
<--- HTTP/1.1 403 Authentication Failed (49ms)
{"status": "error", "reason": "Missing key, signature and nonce parameters.", "code": "API0000"}
<--- END HTTP (96-byte body)
// send as query-parameters
---> POST https://www.bitstamp.net/api/v2/balance/?key=12345678901234567890123456789012&signature=1234567890123456789012345678901234567890123456789012345678901234&nonce=1234567890 HTTP/1.1
Accept: application/json;charset=UTF-8
Content-Type: application/x-www-form-urlencoded
---> END HTTP (0-byte body)
<--- HTTP/1.1 403 Authentication Failed (45ms)
{"status": "error", "reason": "Missing key, signature and nonce parameters.", "code": "API0000"}
<--- END HTTP (96-byte body)
What am I doing wrong? What does bitstamp mean when it states
For a successful authentication you need to provide your API key, a signature and a nonce parameter.
(https://www.bitstamp.net/api/)
I use Feign as REST client. The two methods look like this:
#PostMapping(value = "api/v2/balance/", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
ResponseEntity<Map<String, Object>> getAccountBalanceQuery(#RequestParam("key") String key,
#RequestParam("signature") String signature,
#RequestParam("nonce") Integer nonce);
#PostMapping(value = "api/v2/balance/", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
ResponseEntity<Map<String, Object>> getAccountBalanceBody(#RequestBody BitstampAuth body);
Thanks!

Angular2 - unable to get Set-Cookie from auth. response (jaas, wf)

Iam trying to authenticate from Angular2.1.0 to JAAS form-based j2ee app on WildFly 8.2
let j_username = 'sb2';
let j_password = 'sb222';
let url: string = 'http://127.0.0.1:8888/prototype-rest/j_security_check';
let body = 'j_username=' + j_username + '&j_password=' + j_password;
let headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded'
})
;
//let options = new RequestOptions({headers: headers, withCredentials : true});
let options = new RequestOptions({headers: headers});
this.http.post(url, body, options)
.subscribe(
(res: Response) => {
console.log('res = ' + res);
console.log(res.headers.keys());
var headers = res.headers;
var setCookieHeader = headers.get('Set-Cookie');
console.log('setCookieHeader = ' + setCookieHeader);
},
err => {
console.log('err = ' + err);
}
)
;
response from wildfly
HTTP/1.1 200 OK
Expires: 0
Cache-Control: no-cache, no-store, must-revalidate
X-Powered-By: Undertow/1
Set-Cookie: JSESSIONID=iyD6Yz_Tj7xsIM1zRDHaR2bh.sk-za-04702; path=/prototype-rest
Access-Control-Allow-Headers: accept, authorization, content-type, x-requested-with
Server: WildFly/8
Pragma: no-cache
Access-Control-Expose-Headers: Set-Cookie
Date: Thu, 03 Nov 2016 14:01:41 GMT
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Content-Length: 0
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT
Access-Control-Max-Age: 3600
My problem is that I am not able to read Set-Cookie, if I use withCredentials : true (I am not sure if I should), response fails ... I'd like to add JSESSIONID to request, where I register websocket ...

Retrofit 2: 400 Bad Request when having body

I am trying to perform a status update PUT request. The following example returns 200 in Postman:
URL:
http://www.example.com/users/3/status?seId=1&dt=2016-11-01T00:00:00Z
HEADERS:
Content-Type:application/json
charset:utf-8
Authorization:Bearer LONG_TOKEN_HERE
BODY:
{ "status": 1 }
This is the structure of my Retrofit 2 request:
#PUT("users/{id}/status")
Call<Void> updateEventStatus(#Header("Authorization") String token,
#Path("id") int id,
#Query("seId") int seId,
#Query("dt") String dateTime,
#Body Status status);
The request's URL is the same as in Postman and so are the headers, so I suspect it is related to the body. Status is just a wrapping class with a single int field named status, which I created by following this answer (I did the same with credentials and it works well). I also tried making the status in body of type int but it results in Bad Request as well.
Any idea what could be the difference between the Postman request and the Retrofit 2 request? Thanks!
EDIT: This is the originalRequest in Retrofit 2:
Request{method=PUT, url=http://example.com/api/users/3/status?seId=0&dt=2016-10-04T05:30:00Z, tag=null}
headers: Authorization: Bearer LONG_TOKEN_HERE
contentType: application/json; charset=UTF-8
content:
0 = 123
1 = 34
2 = 115
3 = 116
4 = 97
5 = 116
6 = 117
7 = 115
8 = 34
9 = 58
10 = 51
11 = 125
Translated content:
{"status":3}
Eventually, it was a server-side bug (I received a false seId at first, and then tried to PUT using an seId that doesn't exist).

How can I get Spring MVC+HATEOAS to encode a list of resources into HAL?

I have a Spring HATEOAS Resource such that ModelResource extends Resource<Model>.
In a #RestController I have a method to create new Models:
#RequestMapping(value = "", method = POST)
public ResponseEntity<ModelResource> postModel() {
Model model = service.create().model;
ModelResource resource = assembler.toResource(model);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(resource.getLink("self").getHref()));
return new ResponseEntity<>(resource, headers, CREATED);
}
The created ModelResource returned from the above method is HAL-encoded:
$ curl -v -XPOST localhost:8080/models
> POST /models HTTP/1.1
> User-Agent: curl/7.32.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 201 Created
< Date: Sun, 25 Jan 2015 11:51:50 GMT
< Location: http://localhost:8080/models/0
< Content-Type: application/hal+json; charset=UTF-8
< Transfer-Encoding: chunked
< Server: Jetty(9.2.4.v20141103)
<
{
"id" : 0,
"_links" : {
"self" : {
"href" : "http://localhost:8080/models/0"
}
}
}
In the same controller also have a method to list Models.
#RequestMapping(value = "", method = GET)
public List<ModelResource> getModels() {
return service.find().stream()
.map(modelProxy -> assembler.toResource(modelProxy.model))
.collect(Collectors.toList());
}
For some reason, this method returns plain JSON, not HAL:
$ curl -v localhost:8080/models
> GET /models HTTP/1.1
> User-Agent: curl/7.32.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 25 Jan 2015 11:52:00 GMT
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Server: Jetty(9.2.4.v20141103)
<
[ {
"id" : 0,
"links" : [ {
"rel" : "self",
"href" : "http://localhost:8080/models/0"
} ]
} ]
Why does the first method return HAL, and the second returns plain JSON?
How can I specify consistent behavior?
I've read about #EnableHypermediaSupport, but I don't have it set anywhere in my code.
From this GitHub issue:
That works as expected. HAL defines the top level resource having to
be a document. Thus a plain List by definition cannot be a HAL
document. We've restricted the HAL customizations to only be applied
if the root object to be rendered is ResourceSupport or a subtype of
it to prevent arbitrary objects from getting HAL customizations
applied. If you create a ResourceSupport instead of a List, you should
see a correct HAL document be rendered.
The HAL Primer provides more detail and examples of what such a top-level wrapping resource looks like. In Spring HATEOAS, you use Resources<T> to represent such a wrapper, which is itself a Resource<T> with a self rel:
#RequestMapping(value = "", method = GET)
public Resources<ModelResource> getModels() {
List<ModelResource> models = service.find().stream()
.map(modelVertex -> assembler.toResource(modelVertex.model))
.collect(Collectors.toList());
return new Resources<>(models, linkTo(methodOn(ModelController.class).getModels()).withRel("self"));
}
The returned Resources<T> type is then encoded into a document with embedded documents:
$ curl -v localhost:8080/models
> GET /models HTTP/1.1
> User-Agent: curl/7.32.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 25 Jan 2015 13:53:47 GMT
< Content-Type: application/hal+json; charset=UTF-8
< Transfer-Encoding: chunked
< Server: Jetty(9.2.4.v20141103)
<
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/models"
}
},
"_embedded" : {
"modelList" : [ {
"id" : 0,
"_links" : {
"self" : {
"href" : "http://localhost:8080/models/0"
},
"links" : {
"href" : "http://localhost:8080/models/0/links"
}
}
} ]
}
}
As mentioned above, Resources<T> extends ResourceSupport just like Resource<T>. So you could create a ResourceAssembler for Resources<ModelResource> in order to avoid having to creating the self link by hand, and to generally encapsulate Resource<ModelResource> creation.
This answer suggests that HAL rendering is enabled by Spring Boot if it is available, which explains resources are being rendered HAL when possible.
I expect Spring is automatically choosing application/hal+json as the default Content-Type for all ResponseEntity instances.

Can't get Set-Cookie header from http response

I am developing a small web content scraper . Part of the code is to send a http request and get the cookie from the response header, so it can be set in the subsequent request.
The code to get the cookies is like this:
HttpClient client = HttpClientBuilder.create().build();
HttpGet request = new HttpGet(url);
request.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
request.setHeader("Accept-Encoding","gzip,deflate,sdch");
if(cookie!=null)
{
request.setHeader("Cookie", cookie);
}
request.setHeader("Accept-Language","en-US,en;q=0.8,zh-CN;q=0.6");
request.setHeader("Cache-Control", "max-age=0");
request.setHeader("Connetion", "keep-alive");
request.setHeader("Host", "www.booking.com");
request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64)
AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/32.0.1700.76 Safari/537.36");
try {
HttpResponse response = client.execute(request);
int statusCode = response.getStatusLine().getStatusCode();
System.out.println(statusCode);
//get all headers
Header[] headers = response.getAllHeaders();
for (Header header : headers) {
System.out.println("Key : " + header.getName()
+ " ,Value : " + header.getValue());
}
System.out.println("----------------------------------------------------------");
} catch (HttpException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The url I used to test is http://www.booking.com/hotel/il/herods-hotels-spa.html#tab-reviews
The result printed is like this:
200
Key : Server ,Value : nginx
Key : Date ,Value : Mon, 03 Feb 2014 05:15:41 GMT
Key : Content-Type ,Value : text/html; charset=UTF-8
Key : Connection ,Value : keep-alive
Key : Cache-Control ,Value : private
Key : Vary ,Value : User-Agent, Accept-Encoding
Key : Set-Cookie ,Value : bkng=11UmFuZG9tSVYkc2RlIyh9YdMHS7ByVcpJ6zdHwCKMHsY37i1DyVPCutMoSY%2F9OR7ixF74JFUj1%2BJ3pF8ntbVX55kLQJvNnfE6Qco2NDwnHPzomws7z40vIxLRgwBTWU9CTbAN3zZqJGksaPN3GqHpSWJ%2BMIKlI5hQN6ZcJnKsU3rR9KXmRVS4plyPQf4gqmsjR131%2BtuuBiULzmDsKzejJZg%2BFgWWUOWS71bCxUGvJbeBBo1HRmUVmigKDEyHylYplnhKkriMof25dYccWyLQoBjIyUL4QZWr58O5D7fKPHDYWSY9y7k%2Bxfk7irIsyKdu%2B0owjpGp2%2BncNdphtqPZqdpeCyky1ReSjWVQ4QuZemceNGmfZGwxm%2BQxu0%2BkBEsJA5zY%2BoqulR8MJIBKZpFqsuvbeDZ9r5UJzl5c%2Fqk7Vw5YU1I%2FQunbw7PHra7IaGp6%2BmHnH2%2BeyiMDhAjWL769ebuwG2DhrgfB6eI0AGZE%2F6T0uA4j7bxA%2FwUdhog6yOu%2FSeTkPl%2FTAiIetVyKLfT1949ggWKfk1kGzmjnowOlZzPbxr1L%2FAifBjInWZ6DreY1Mr2A3%2BfjFYaHJYnS8VpB%2BZappBpGXBUVfHe%2FQ7lbDwNd6TCCzigpsb17LtvFYsb3JiZ%2BQFF82ILNwWFKz6B1xxEEbCRVoq8N%2FcXXPStyGSwApHZz%2Bew6LNI7Hkd2rjB1w3HenUXprZWR3XiWIWYyhMAbkaFbiQV2LThkl2Dkl%2FA%3D; domain=.booking.com; path=/; expires=Sat, 02-Feb-2019 05:15:41 GMT; HTTPOnly
Key : X-Recruiting ,Value : Like HTTP headers? Come write ours: booking.com/jobs
However when I uploaded this small program to my server, and ran it, the result became:
200
Key : Server ,Value : nginx
Key : Date ,Value : Mon, 03 Feb 2014 05:14:14 GMT
Key : Content-Type ,Value : text/html; charset=UTF-8
Key : Connection ,Value : keep-alive
Key : Cache-Control ,Value : private
Key : Vary ,Value : User-Agent, Accept-Encoding
Key : X-Recruiting ,Value : Like HTTP headers? Come write ours: booking.com/jobs
The Set-Cookie header disappeared and my subsequent requests to other content pages within the same site(which are supposed to be loaded by a javascript in the first page I requested) all returned 400 error which I guess is because the cookie missing.
I can't figure out why, and the differences between my pc and the server that I know are:
My pc is running Windows 7 and actually has a Chrome browser, while the server is running Linux and doesn't have any actual browser.
The ip addresses are different.
Other than these, I can't think of any yet.
Any suggestion or advice to solve this problem will be appreciated. Thank you.
set-cookie is a forbidden response header name, you can't read it using browser-side JavaScript
developer.mozilla.org
Browsers block frontend JavaScript code from accessing the Set Cookie header, as required by the Fetch spec, which defines Set-Cookie as a forbidden response-header name that must be filtered out from any response exposed to frontend code.

Categories