Sending a JSON POST request with BSF Preprocessor - javascript

I am working with JMeter to write some performance tests. One of the things that I need to do is to construct a huge json request dynamically and send it as POST request paylod. Using BSF preprocessor, I am able to modify the payload dynamically however my javascript string is being encoded, while I want to send it without being encoded.
I am not sure how BSF preprocessor can stop it from being encoded. The command I currently use to change my POST request payload is as follows:
var jsonData = '[{"item":"value","something":"everything"}]';
sampler.addArgument("",jsonData);
I would really appreciate if you can point me to some examples which clearly explain how bsf preprocessors are expected to be used.
Any pointers to skip the encoding will also be appreciated.

Since JMeter 2.6 you can use the RAW request pane using Post Body tab.
So your solution is to do the following:
In BSF Sampler, put you JSON in a variable:
var jsonData = '[{"item":"value","something":"everything"}]';
vars.putObject("jsonData",jsonData);
In Post Body, put:
${jsonData}
Another option using your method is to put in BSFPreProcessor using Beanshell language (not javascript):
import org.apache.jmeter.protocol.http.util.HTTPArgument;
String jsonData = "[{\"item\":\"value\",\"something\":\"everything\"}]";
HTTPArgument arg =new HTTPArgument("", jsonData, null, true);
arg.setAlwaysEncoded(false);
sampler.getArguments().addArgument(arg);
Regards
Philippe M.

set property on your sampler "HTTPArgument.always_encode" to false this should disable argument encoding

Related

Asana API - upload files using Ajax

I have a project that requires file uploads into Asana. I would like to be able to do this through Asana's API if possible. I have been able to successfully create tasks in Asana using Ajax Post requests. Is there anyway to use an Ajax Post request to upload a file to an Asana task? I would like to be able to upload files straight from an HTML FileUplaod Object. Does anyone know if this is possible?
I have tried Posting an JSON object like this to the attachments API, but this did not work.
https://app.asana.com/api/1.0/tasks/{taskID}/attachments
{
"parent": 1337,
"download_url": "https://www.dropbox.com/s/1234567890abcdef/Screenshot.png?dl=1",
}
I also don't want to post using a url, I want to post directly from the FileUpload object, if possible.
The short answer is to check out this other stack overflow question, which has a pretty good description of how to pull this off. sending a file as multipart through xmlHttpRequest
The long answer is this:
Uploading files has a different "feel" than most of the rest of our API, because the attachments endpoint expects to take content of Content-Type: multipart/form-data. There are several main things you have to get just right for this to work:
You have to set that Content-Type request header to multipart/form-data and to also in that header set the key boundary to be a unique, preferably long boundary to delimit the file, let's use 1z2x3c4v5b for this example.
You start the upload's body with 2 dashes and the boundary, i.e. --1z2x3c4v5b, followed by a newline
Still in the upload body, after the delimiter you have to provide some "headers" specifying Content-Disposition and Content-Type correctly for the file (i.e. what type of image it is, what its name is, that sort of thing)
2 newlines
The raw bytes of the file
2 newlines
2 dashes, the delimiter, and 2 final dashes, i.e. --1z2x3c4v5b--
Please note how all these features come together in the example in our Attachments documentation. This song-and-dance, which has to be done just right is what the author of that other SO post meant with "XHR will take care about proper headers and request body encoding". You can attempt to pull this off yourself, but I would recommend the approach they outline because it's by far the easiest.
I was able to solve this using the following code.
function addAttachment(taskID)
{
var data = new FormData();
data.append("file", document.getElementById("fileUploader").files[0]);
var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://app.asana.com/api/1.0/tasks/"+taskID+"/attachments");
xhr.setRequestHeader("authorization", "Bearer <access-token>");
xhr.send(data);
}

Is jQuery / Backbone mangling my UTF-8 characters?

I'm migrating the front-end of a site from an old YUI2 framework to jQuery/BackBone. The PHP/mySQL back-end hasn't changed. All is well, except UTF-8 characters sent via Backbone save (via $.ajax) are getting mangled and I can't figure out why.
Here's what I do know:
The backend handles UTF-8 fine. It hasn't changed as part of this rebuild. I know that's true, because when I change the config to load the old YUI2 front-end, UTF-8 characters work fine. They're escaped in Javascript using escape(string), passed via YAHOO.util.Connect.asyncRequest as JSON in an XMLHttpRequest, unescaped and saved in the database as UTF-8, fully readable and nice.
In the new front-end, I've added <meta charset="UTF-8"> and <meta http-equiv="content-type" content="text/html; charset=UTF-8"> to all page headers. The old front-end didn't have these settings. I only mention that because it's a difference.
In the new front-end, UTF-8 characters work fine when I save them as a <form> submit.
I the new front-end, the request Content-Type looks fine in the console. Content-Type:application/x-www-form-urlencoded; charset=UTF-8
How am I passing data in the new front-end?
Sometimes via a regular Backbone model.save(), other times passing data in options like this:
var text = $('#input-' + targetId).val();
var atts = {};
atts['target_id'] = targetId;
atts['user_id'] = userId;
atts['text'] = text;
var comment = new Comment(atts);
comment.save(
{},
{
type: 'POST',
url: '/api/comment?',
data: atts,
processData: true,
success: function(comment, response){
//success handling
},
error: function(model, response){
//error handling
},
},
);
So, what do these mangled special characters look like?
As entered in the input: テクス テクサン テクス テクサン
When I pass completely unescaped, they look fine in the request in the console in the Form Data section: text: テクス テクサン テクス テクサン, but mangled in the database as ãã¯ã¹ ãã¯ãµã³ ãã¯ã¹ ãã¯ãµã³. Perhaps this is a clue, I don't know. I've always escaped user-entered text when passing via AJAX.
When I escape(text), I get text:%u30C6%u30AF%u30B9%20%u30C6%u30AF%u30B5%u30F3%20%u30C6%u30AF%u30B9%20%u30C6%u30AF%u30B5%u30F3 in the console, and テクス%20テクサン%20テクス%20テクサン in the database.
That's better, but it's different from the old front end, which uses escape(text), passes %u30C6%u30AF%u30B9%20%u30C6%u30AF%u30B5%u30F3%20%u30C6%u30AF%u30B9%20%u30C6%u30AF%u30B5%u30F3, shows in the console as text: (unable to decode value) and saves in the database unescaped as テクス テクサン テクス テクサン
Of course, it's 2016 now and we all know escape() should not be used. We should use encodeURIComponent() instead. So, when I encodeURIComponent(text), here's what I get in the console: text: %E3%83%86%E3%82%AF%E3%82%B9%20%E3%83%86%E3%82%AF%E3%82%B5%E3%83%B3%20%E3%83%86%E3%82%AF%E3%82%B9%20%E3%83%86%E3%82%AF%E3%82%B5%E3%83%B3 which is saved in the database as %E3%83%86%E3%82%AF%E3%82%B9%20%E3%83%86%E3%82%AF%E3%82%B5%E3%83%B3%20%E3%83%86%E3%82%AF%E3%82%B9%20%E3%83%86%E3%82%AF%E3%82%B5%E3%83%B3 That technically works, and I can always decodeURIComponent when displaying this text, but that's a real pain and it's just masking the issue.
I've also tried unescape(encodeURIComponent(text)) with the following result: text:ãã¯ã¹ ãã¯ãµã³ ãã¯ã¹ ãã¯ãµã³ in the console, ãÂÂã¯ã¹ ãÂÂã¯ãµã³ ãÂÂã¯ã¹ ãÂÂã¯ãµã³ in the database.
It seems that there's some sort of double-encoding going on, or perhaps the back-end was built to handle the specific format that's passed via the YUI2 Async request. I don't know.
Any ideas for what I should try next? What are the best practices?
Now that I've had a night to sleep on it, I've realized a few things and I think I've found a solution.
It's clear now that the old front-end wasn't passing data correctly...that's evidenced by the text: (unable to decode value) in the console when sending the request. Somehow, the PHP back-end was able to handle the passed text even though there was no decoding in the api or db storage classes. That's a mystery for another day.
Here's what I did to fix the problem:
Pass text from the front-end as encodeURIComponent(text)
Decode the text in the PHP back-end api using $comment->set_text(urldecode(Request::get('text')));
The text is stored in the DB unescaped as readable UTF-8 characters and I don't need to do anything special on read/display. I will need to add the urldecode to all of my api endpoints on the back-end, but that feels like a solid approach, so I think it's resolved.
I'd be interested to hear thoughts on the use of encodeURIComponent on the front-end and urldecode on the back-end. Is this the best way to solve the problem?

PHP $_GET and underlines

I have a very short piece of PHP that I use to make HTTP requests from JavaScript.
<?php echo file_get_contents($_GET['url']); ?>
I have used it successfully in a few projects, but am running into a problem with making requests in my current project. Based on my searching, I believe it may be caused by the underscore in the request, though through my searching and not knowing PHP, I have not been able to confirm that.
Below is an example of what I am doing from JavaScript:
$.get("grabber.php?url=" + "http://tidesandcurrents.noaa.gov/api/datagetter?station=8573364&begin_date=20160202&end_date=20160203&product=predictions&units=english&time_zone=gmt&format=json&application=poseidonweathercom+&datum=MLLW", function(forecast) {
console.log(forecast);
});
If I copy the url and put in it in a browser, I get back the JSON that I requested. When I use the code above, I end up getting an error message from NOAA:
Wrong Product : Product cannot be null or empty Wrong Time zone: Time zone cannot be null or empty Wrong Unit:Unit cannot be null or empty Wrong Format: Format cannot be null or empty Wrong Date: The beginDate cannot be null or empty
Do I need to use a regex for the underscore in PHP? Is there some other issue that I do not understand?
Thanks.
You need to send it encoded, which will convert all the underscores/spaces/ampersands etc. with their encoded equivalents:
var url = "http://tidesandcurrents.noaa.gov/api/datagetter?station=8573364&begin_date=20160202&end_date=20160203&product=predictions&units=english&time_zone=gmt&format=json&application=poseidonweathercom+&datum=MLLW";
$.get("grabber.php?url=" + encodeURIComponent(url), function(forecast){
console.log(forecast);
}
Using encodeURIComponent() on that URL shows:
http%3A%2F%2Ftidesandcurrents.noaa.gov%2Fapi%2Fdatagetter%3Fstation%3D8573364%26begin_date%3D20160202%26end_date%3D20160203%26product%3Dpredictions%26units%3Denglish%26time_zone%3Dgmt%26format%3Djson%26application%3Dposeidonweathercom%2B%26datum%3DMLLW
Alternatively, if you just want to access the JSON data and handle it within the JavaScript function, you can retrieve the data via the URL directly, without having to encode the URL:
$.get("http://tidesandcurrents.noaa.gov/api/datagetter?station=8573364&begin_date=20160202&end_date=20160203&product=predictions&units=english&time_zone=gmt&format=json&application=poseidonweathercom+&datum=MLLW", function(forecast) {
console.log(forecast);
});
Um why do you even need your php code ... the code below will work just fine and eliminate your server overhead.
$.get("http://tidesandcurrents.noaa.gov/api/datagetter?station=8573364&begin_date=20160202&end_date=20160203&product=predictions&units=english&time_zone=gmt&format=json&application=poseidonweathercom+&datum=MLLW", function(forecast) {
console.log(forecast);
});

How do I modify the accept headers for a GET request (outside of ajax) on the client side?

I have a download to Excel button on a page whose intent is to call the exact same URL, but with the Request Header set to "application/ms-excel".
Currently, I am faking it, by calling another URL, then adjusting the headers and then forwarding to the same function.
Server-side (Django):
HTTP_HEADER_EXCEL = "application/ms-excel"
#fake testing url
#http://localhost:8000/myfunction/<CLASSID>/xls/
def myfunction_xls(request, CLASSID):
#intercept request, add the appropriate accepts
#and forward it
request.META["HTTP_ACCEPT"] = HTTP_HEADER_EXCEL
request.META["dbr"] = dbr
return myfunction(request, CLASSID)
#standard url
#http://localhost:8000/myfunction/<CLASSID>/
def myfunction(request, CLASSID, f_callback=None):
if request.META["HTTP_ACCEPT"] == HTTP_HEADER_EXCEL:
f_callback=provider.generateExcel
....do lots of work...
di_context = dict(inst=inst,
parent=inst,
custom=custom,
url_excel=url_excel,
if f_callback:
#use xlsxwriter to process di_context data
#wrap up the appropriate response headers
#and it appears as a download (it works)
return f_callback(request, di_context)
#non-Excel branch, i.e. standard Django behavior
t = get_template('pssecurity/security_single.html')
c = RequestContext(
request,
di_context,
)
html = t.render(c)
return HttpResponse(html)
My problem is that I don't want to maintain a custom URL just for Excel (or adding an optional /xls/ to the regex for the url. Perfectly OK using the existing url, and having the server adjust on the basis of the accepts headers. And, yes, I could add query parameter to indicate xls, but... isn't my particular requirement what accept headers are for?
I found a discussion about how to do this in Ajax, but that's not necessary here. Perfectly happy with a regular GET (not POST) request that happens to specify application/ms-excel.
I know I can't specify the accepts using the href attribute. And, while window.open() in javascript would do the trick just fine, I don't see any way to change the accept headers there either.
Hmmm, yes, may be a web noob question, but I can't find much about easily modifying accept headers outside of $http or $ajax trickery.

JMeter modifying output to file from XML Stream

I'm attempting to write a JMeter script which after receiving and XML response from a server, extracts a string from it on the fly (drops the first part of the response) and writes it to a file.
Currently I use a Save Response Data to write to ChannelData_UAT_1 (filename). All good, it writes happily.
Then I add a BSF PreProcessor BEFORE it, and use javascript to try and extract the string. It's a bunch of XML tags, I want everything from "<Markets>" onwards.
I use:
function extract_markets(str)
{
marketIndex = str.indexOf("<Markets");
__log(marketIndex);
length = str.length;
marketString = str.substring(markeIndex, length-1);
return str;
}
vars.put('ChannelData_UAT_1', extract_markets(vars.get('ChannelData_UAT_1')));
As far as I can tell, ChannelData_UAT_1 is the variable the data is in. However this is only mentioned in the Save Response Data. But I can't do it afterwards otherwise it'll have already written to the file.
The current performance is for it to receive the response and write to the file. No filtering is done - as if my javascript didn't exist.
Anything small or obvious that I've missed? Suggestions?
I believe the issue stems from the fact that ChannelData_UAT_1 is not a variable and how Save Response Data works.
ChannelData_UAT_1 is the file name, not the content of the file.
You need to modify the contents of the "Response". You can replace the value of the page response with the value of your function.
I think the code would look something like this:
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.samplers.SampleResult;
prev.setResponseData(extract_markets(vars.get('ChannelData_UAT_1')));
Source:
http://www.javadocexamples.com/java_examples/org/apache/jmeter/samplers/SampleResult/

Categories

Resources