Ask a Question

Virtual service: reading the request headers in code injected into a response

swalchemist
Occasional Contributor

Virtual service: reading the request headers in code injected into a response

Hi, SmartBear Customer Care sent me here when they couldn't find an answer for me.

 

We have set up a virtual service with ReadyAPI that's working well when we run it locally, and it's also working when we run it in a virtserver and have only one user accessing it. The service is keeping a small amount of state to simulate changes to a database. We used a simple load test to show that our service has a race condition that can cause it to return the wrong data up to 10% of the time, so we can't recommend rolling out the service to our broader organization yet.

 

We're trying to support the stateful service for multiple users by reading a "clientId" header in the request and dynamically generating the name of a property in order to look up its current value that can be unique for each client (the value is set in a different request). What's working for a single user now is that we have script code that sets the property, and then we inject this code into the response to return the per-client property value:

mode="${#MockService#${#MockService#clientId}-mode}"

 

This fails our load test probably because the time between running the script code to set the (global) property and running the code in the response gives an opportunity for another request to overwrite the property value.


To be clear: we have script code for this response (not shown here) that sets the property, and to inject a value into the response, we also have the code above directly in the response that reads both the clientId and the unique property value for the client. The scripting environment and the syntax for code in the response is somewhat different than in the script, and we have found very little documentation on what we can do with this code in the response.

One fix we tried didn't work, where we tried to access objects that are available in script code:

mode="${=def clientId = mockRequest.getRequestHeaders().get("myClientId").get(0); context.expand("#MockService#" + clientId + "-mode")}'"


Turns out we can't access mockRequest in the response:
  mode="No such property: mockRequest for class: Script36'"

I know we can store these per-client properties in headers instead of properties, but for that to work, we still have to figure out how to read the request headers in the response code. Anyone have ideas for a solution?

9 REPLIES 9
nmrao
Community Hero

One can access both the request and its headers in the mock service though I may not suggest running load test against mock service.

Below is the sample project which uses Script Dispatch and has sample for accessing both request and its headers.
https://github.com/nmrao/sample-soapui-projects/tree/master/scriptDispatch


Regards,
Rao.
swalchemist
Occasional Contributor

Hi, @nmrao. That's a nice example of reading headers in the dispatch script. But your project doesn't have any code injected directly in the response, and that's where we're not able to use the kind of code you're using in the dispatch script to access the request headers.

 

This does give me the idea that we could generate every combination of responses in a different hardcoded response file and choose one of them using the dispatch script. Right now it's just two boolean values, so there are four combinations, but that's likely to increase soon and create a maintenance problem.

 

On the topic of load tests - the SmartBear documentation does suggest doing a load test. We didn't need a heavy load to demonstrate the problem, just 2 or 3 concurrent threads, so we used only the minimum load necessary.

May be I didn't read the inject part by looking just read part.

Of course one can inject as well, otherwise not possible for sending dynamic value in response. Will find a sample.


Regards,
Rao.

Please see if below video helps
https://youtu.be/L2SMZ9bbDvE


Regards,
Rao.
swalchemist
Occasional Contributor

Hi, @nmrao. I watched the video, and he is injecting properties into the response in a similar way that we're doing it. I believe his code has a similar vulnerability that we have - it's possible for two clients to get the same value in a response from his virtual service, but his intention was for each response to be random.

Would you clarify what exactly you need and what you tried and what is not not working? That will help to find the solution.


Regards,
Rao.
swalchemist
Occasional Contributor

 This is not working when I use this as a response:

mode="${=def clientId = mockRequest.getRequestHeaders().get("myClientId").get(0); context.expand("#MockService#" + clientId + "-mode")}'"

 The problem is that "mockRequest" is not made available to code that is injected in a response like this (only in code in the script pane). Is there any way to read the request headers from code in the response?

 

We have some code in another response that modifies dates - this is working fine.

 

Other ideas on how to maintain state for multiple users of the virtual service is welcome. That state will affect the content of the responses.

Not sure I understand.
Is it that a value from request needs to be into the response?
Are you working with SOAP or REST?


Regards,
Rao.
swalchemist
Occasional Contributor

Basically, yes. It's a bit more complex - a value in the request header will be used by the code to determine which property to include in the response. But if I can figure out how to reliably echo back a request header in the response, then I can figure out the rest.

I'm virtualizing an xmlrpc service, which I'm treating as a REST service in ReadyAPI. The sample response using the "${=   }" syntax I gave in the last message is in the Response -> Edit pane on the outgoing response.

cancel
Showing results for 
Search instead for 
Did you mean: