I don't seem to be able to call DELETE methods via Restler for some reason. In my restler php file I've defined a method like so:
/**
* Drop invitation
*
* Removes an invitation from the system. Coaches want a way to be able
* to remove an invite if they messed up, or the person just doesn't accept.
*
* #param string $email The email address of the invited person {#from body}
* #param int $team_id The SQL identifier for the team {#from body}
*
* #return array An empty array
*/
public function deleteInvite($email, $team_id) {
return [];
}
When I try to call it:
curl -X DELETE -H "Content-Type: application/json" -d '{"email":"foo","team_id",17}' http://server.com/app/team/invite
It comes back with a 400 error:
{
"error": {
"code": 400,
"message": "Bad Request: email is missing."
}
}
How am I supposed to be calling this?
as a widely accepted practice restler does not support/read body parameters for GET and DELETE requests. Send them on url or as a query string instead.
As you can see in https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-p2-semantics-26#section-4.3
HEAD - No defined body semantics.
GET - No defined body semantics.
PUT - Body supported.
POST - Body supported.
DELETE - No defined body semantics.
TRACE - Body not supported.
OPTIONS - Body supported but no semantics (maybe in the future).
Many http servers do not parse the body of GET and DELETE requests, restler is following that practice
Related
HI there I am making post call using karate And for that I am passing json Payload but before i pass it i want to validate is there any null or empty string present and if yes then Abort the post call and print message empty string or null values cant be accepted.
Thanks in advance!
peter thomas Thank you in advance
This doesn't make sense to me, because if you are preparing this payload yourself, you never need to validate it.
That said, you can run a match anytime.
* def body = { myKey: 'myValue' }
* match body == { myKey: '#string' }
* url 'https://httpbin.org/anything'
* request body
* method post
* status 200
* match response contains deep { json: { myKey: 'myValue' } }
See how the second line does a validation.
Also refer this answer to see how you can programmatically run karate.match() for advanced use-cases: https://stackoverflow.com/a/50350442/143475
The following code is part of a controller in a Quarkus Microprofile API application.
#GET
#Path("/limit/{limit}/offset/{offset}")
#Produces(MediaType.APPLICATION_JSON)
public Response paginatedAccounts(
#Parameter(
description = "Number of records to be returned.",
required = true,
schema = #Schema(type = SchemaType.INTEGER))
#PathParam("limit") int limit,
#Parameter(
description = "The starting number of record, zero based.",
required = true,
schema = #Schema(type = SchemaType.INTEGER))
#PathParam("offset") int offset)
{
return Response
.ok(this.accountService.getPaginatedAccounts(limit, offset))
.build();
}
It returns a paginated list of accounts.
When user calls the API providing a wrong type for "limit" or "offset", ie:
http://[url]/[entity]/limit/zzz/offset/0
she receives "404 - Not Found"
How to validate the parameters "limit" and "offset" so that when user supplies a wrong type (string for int) she receives instead:
"400 - Bad Request"
as it should be?
This is by design (of the JAX-RS spec).
https://docs.oracle.com/cd/E19798-01/821-1841/6nmq2cp1v/index.html mentions it explicitly:
If the URI path template variable cannot be cast to the specified type, the JAX-RS runtime returns an HTTP 400 (“Bad Request”) error to the client. If the #PathParam annotation cannot be cast to the specified type, the JAX-RS runtime returns an HTTP 404 (“Not Found”) error to the client
I started using ZAP and I really like it so far but I miss an option or maybe I don't find it. Burp has an payload mode called "pitchfork" where you can increment two payloads at a time. Got ZAP anything like this?
Thanks
I just realized that what I'd given you was actually Battering ram not Pitchfork.
https://portswigger.net/burp/documentation/desktop/tools/intruder/attack-types
For Pitchfork you'd simply define two fuzz locations and specify two different lists. Easy peasy.
Here's how you'd accomplish what you need.
Assume the following request for my answer/example:
GET http://localhost:8090/bodgeit/product.jsp?typeid=3&foo=3 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Host: localhost:8090
Let's say that typeid and foo are the param values that you want to pitchfork. Your going to create a Payload Generator script in ZAP, such as the following (this is a simple minor tweak to the default template, the important differences are outlined below after the code sample):
// Auxiliary variables/constants for payload generation.
var NUMBER_OF_PAYLOADS = 10;
var INITIAL_VALUE = 1;
var count = INITIAL_VALUE;
var MID= '&foo='
/**
* Returns the number of generated payloads, zero to indicate unknown number.
* The number is used as a hint for progress calculations.
*
* #return {number} The number of generated payloads.
*/
function getNumberOfPayloads() {
return NUMBER_OF_PAYLOADS;
}
/**
* Returns true if there are still payloads to generate, false otherwise.
*
* Called before each call to next().
*
* #return {boolean} If there are still payloads to generate.
*/
function hasNext() {
return (count <= NUMBER_OF_PAYLOADS);
}
/**
* Returns the next generated payload.
*
* This method is called while hasNext() returns true.
*
* #return {string} The next generated payload.
*/
function next() {
payload = count;
count++;
return payload+MID+payload;
}
/**
* Resets the internal state of the payload generator, as if no calls to
* hasNext() or next() have been previously made.
*
* Normally called once the method hasNext() returns false and while payloads
* are still needed.
*/
function reset() {
count = INITIAL_VALUE;
}
/**
* Releases any resources used for generation of payloads (for example, a file).
*
* Called once the payload generator is no longer needed.
*/
function close() {
}
Note: Declaration of the MID constant, which is the middle part of the string between the two param values. Modification of the next() method which returns the same value for both param values with the "MID" string inserted between.
In the request highlight 3&foo=3 right click and select "Fuzz...". Click the "Payloads" button, click the "Add" button, set the "Type" dropdown as "Script", select your "Script" by name in the dropdown (I called mine "Pitchfork"). ("Generate Preview" if you like.) Click the "Add" button. Click the "Ok" button. Click "Start Fuzzer". You've now run a "Pitchfork" fuzz in ZAP.
Results in the following payloads:
1&foo=1
2&foo=2
3&foo=3
4&foo=4
5&foo=5
6&foo=6
7&foo=7
8&foo=8
9&foo=9
10&foo=10
Things to keep in mind:
Assuming you're fuzzing a normal GET or POST you should be able to order the params however you like. (Targets "shouldn't" care which order params are in, you can copy/paste them into whatever order you need and send the request manually.) If it's some sort of well formed content (JSON/XML, or whatever) then you can just turn MID into a huge string...
You can install/use a scripting add-on such as Python (Jython) if you want to access payloads from a file.
If you wanted to process a header based on the same payload as the initial injection then you'd do a slight variation.
Create a "Fuzzer HTTP Processor" script, which is just a slight variation on the template. The following example simply checks the value of the payload in foo and uses it in a header:
/**
* Processes the fuzzed message (payloads already injected).
*
* Called before forwarding the message to the server.
*
* #param {HttpFuzzerTaskProcessorUtils} utils - A utility object that contains functions that ease common tasks.
* #param {HttpMessage} message - The fuzzed message, that will be forward to the server.
*/
function processMessage(utils, message) {
// To obtain the list of payloads:
// utils.getPayloads()
// To obtain original message:
// utils.getOriginalMessage()
// To stop fuzzer:
// utils.stopFuzzer()
// To increases the error count with a reason:
// utils.increaseErrorCount("Reason Error Message...")
// To send a message, following redirects:
// utils.sendMessage(myMessage)
// To send a message, not following redirects:
// utils.sendMessage(myMessage, false)
// To add a message previously sent to results:
// utils.addMessageToResults("Type Of Message", myMessage)
// To add a message previously sent to results, with custom state:
// utils.addMessageToResults("Type Of Message", myMessage, "Key Custom State", "Value Custom State")
// The states' value is shown in the column 'State' of fuzzer results tab
// To get the values of the parameters configured in the Add Message Processor Dialog.
// utils.getParameters()
// A map is returned, having as keys the parameters names (as returned by the getRequiredParamsNames()
// and getOptionalParamsNames() functions below)
// To get the value of a specific configured script parameter
// utils.getParameters().get("exampleParam1")
// Process fuzzed message...
var payload = null;
for (var iterator = message.getUrlParams().iterator(); iterator.hasNext();) {
var urlParam = iterator.next();
if (urlParam.getName() == 'foo') {
payload = urlParam.getValue();
break;
}
}
message.getRequestHeader().setHeader("X-Some-Id", payload);
}
/**
* Processes the fuzz result.
*
* Called after receiving the fuzzed message from the server.
*
* #param {HttpFuzzerTaskProcessorUtils} utils - A utility object that contains functions that ease common tasks.
* #param {HttpFuzzResult} fuzzResult - The result of sending the fuzzed message.
* #return {boolean} Whether the result should be accepted, or discarded and not shown.
*/
function processResult(utils, fuzzResult){
// All the above 'utils' functions are available plus:
// To raise an alert:
// utils.raiseAlert(risk, confidence, name, description)
// To obtain the fuzzed message, received from the server:
// fuzzResult.getHttpMessage()
// To get the values of the parameters configured in the Add Message Processor Dialog.
// utils.getParameters()
// A map is returned, having as keys the parameters names (as returned by the getRequiredParamsNames()
// and getOptionalParamsNames() functions below)
// To get the value of a specific configured script parameter
// utils.getParameters().get("exampleParam1")
return true;
}
/**
* This function is called during the script loading to obtain a list of the names of the required configuration parameters,
* that will be shown in the Add Message Processor Dialog for configuration. They can be used
* to input dynamic data into the script, from the user interface
*/
function getRequiredParamsNames(){
return [];
}
/**
* This function is called during the script loading to obtain a list of the names of the optional configuration parameters,
* that will be shown in the Add Message Processor Dialog for configuration. They can be used
* to input dynamic data into the script, from the user interface
*/
function getOptionalParamsNames(){
return [];
}
You'd select just the param value you want to fuzz. In the above example if you wanted to fuzz foo you'd just select the 3. Setup the fuzzer much as above (you could use a built-in generator instead of a script), but add your "Message Processor" in the "Message Processors" tab, run the fuzzer.
Based on this example foo should get the values 1 thru 10 and each request will have a header such as X-Some-Id: 1 added (where the Id is 1 to 10 kept in pace with the payload).
Of course you could also do a substring, encoding, etc. it doesn't have to be exactly the same.
I have a really simple controller (with FOSRESTBundle)
/**
* #Rest\Post("/posts/{id}/attachments", name="api_create_attachment", requirements={"pId"="\d+"})
* #Rest\View()
*/
public function createAttachments(Request $request)
{
/** #var UploadedFile $attachment */
$attachment = $request->files->get('file');
return $attachment->getFilename();
}
I just want to dump the filename from POST request of /api/posts/{id}/attachments. I use Postman with the Content-Type: multipart/form-data header for allowing the file to be send.
Now, i have two files (pp.jpg: 163kb and para.jpg: 358kb). When i try to send the request with pp.jpg it's working perfectly and it return "phpyl3yNE" (the filename). But now, when i'm trying with para.jpg which is not really different, it return me an error "Call to a member function getFilename() on null". And it's the same with many differents files ! I can't figure out why ... i use the symfony serve command for the server and from phpinfo, post_max_size is set to 8M and upload_max_filesize is set to 2M.
I'm stuck at this point .. I can't figure out why it return me null ...
Thank you, have a nice day !
I am new to restler and trying to do the following things, can't seem to get hold of it
I have this class and method exposed via Restler
class Account {
protected $Api_Version = array('version' => "1.0.2.1234", 'href' => "/");
// Returns the version of the service
// Content-Type: application/vnd.cust.version+json
function version() {
return json_encode($this->version);
}
// Accepts only Content Type: application/vnd.cust.account+json
function postCreate() {
}
}
1) I want to return my own Content-Type to client like in the 'version' method instead of default application/json. In my case its 'application/vnd.cust.version+json'
2) Method postCreate should only accept the request if the Contet-Type is set to 'application/vnd.cust.account+json'. How to check if that header is set in the request.
3) Also in the restler API Explorer, for methond name, how can I show only the method name instead of the 'version.json'. I want to show just 'version' like the method name
Thank you for your help.
Narsi
1) maybe Write your own format? Take a Look at
http://restler3.luracast.com/examples/_003_multiformat/readme.html
2) you could check the headers and throw Exception on wrong one.
Take a Look at this link
http://stackoverflow.com/questions/541430/how-do-i-read-any-request-header-in-php
3) have you tried to and the following line to your Index.php?
Resources::$useFormatAsExtension = false
Hope takes you further on :)
CU
Inge