Jump to content

Puzzle/challenge: making a link or button perform a POST request


jhsachs

Recommended Posts

Here's a problem for anyone who likes JavaScript puzzles and has too much time on their hands!

 

For the sake of security, I wanted to pass all of a site's parameters via POST requests. This works fine as long as the design is limited to forms, but I was working with an existing site that has hundreds of links and dozens of buttons. I know it's possible to gin up a form with submit buttons that look like links, but the code is messy, and there were all sorts of situations that would have required special treatment; for example, buttons that contain images and links that span line breaks.

 

I decided to solve the problem by coding links and buttons, and running a JavaScript function in the onclick event to move the URL and parameters into a hidden form, then submit the form.

 

The idea was that a link like this...

 

<a href="gerbils.php?wheel=yes">Gerbils!</a>

 

...would be recoded like this:

 

<a onclick="return SetLoad(this);" href="gerbils.php?wheel=yes">Gerbils!</a>

 

Every link would have to be changed, but the change would be simple and absolutely consistent.

 

I tried it.

 

It works.

 

In Firefox 10.

 

When I tried the fully "debugged" code in Internet Explorer 8 and Chrome 19, it failed in two different ways. IE appeared to execute the entire JavaScript function, then do a GET request as if the function had done nothing. Chrome wouldn't execute the function at all.

 

At this point I decided to abandon the approach. I don't have experience debugging JavaScript in IE or Chrome, and a brief trial convinced me that in Chrome, at least, it would not be a walk in the woods.

 

The technique I tried to implement seems elegant and useful, though... if it can be made to work in other browsers.

 

That's the challenge. Whoever completes it will have my undying gratitude and a useful piece of code!

 

Here's the code I've got:

 

function SetLoad(id) {
   alert("We got here");
   if ( typeof(id)=='string' ) {              // This tag.
      var obj = document.getElementById(id);  //  id="x" onclick='return SetLoad("x")'
   }
   else if (id) {
      var obj = id;                           //  onclick='return SetLoad(this);'
   }
   else {
      var obj = document.activeElement;       //  onclick='return SetLoad();'
   }
   if ( obj.tagName=='BUTTON' ) {             // If it's a button
      var href = obj.value;                   //  get its value
   }
   else {                                     // else
      var href= obj.href;                     //  it's an anchor; get its href.
   }
   var qPos = href.indexOf('?');              // Position of '?'
   var pars = '';                             // Value of parameter string if any
   if (qPos>=0) {                             // If there is a '?'
      pars = href.substr(qPos+1);             //  par = the following substring
      href = href.substr(0,qPos);             //  href = the preceding substring
   }
   document.load.action = href;               // Set the form's target
   document.load.params.value = pars;         // Set the params field's value
   document.load.submit();                    // Submit the form
   return false;
}

 

It operates on this form:

 

<form name="load" method="POST" action="genX.php">
   <?php passTokens() ?>
   <input type="hidden" name="params" value="xxxxxxxxxxx"/>
</form>

 

Each script that expects parameters must "unpack" them from the "params" parameter by calling this PHP function:

 

/**
* <p>Parse $_POST['params'] and replace it with its components.</p>
* <p>This makes a script loaded by BodySuffix.inc's "load" form act like a conventionallyl loaded
* script.</p>
*/
function parsePOST() {
   if ( !key_exists('params',$_POST) )
      { return; }
   $params = $_POST['params'];
   if ( !isPOST('tokenS') || !isPOST('tokenP') || !isPOST('loadBy') ){
      $msg = "tokenS, tokenP, or loadBy is missing:\n" . var_export($_POST,true);
      atrain_log(null,null,null,$msg);
      atrain_exit($msg);
   }
   $_POST = array( 'tokenS'=>$_POST['tokenS'], 'tokenP'=>$_POST['tokenP'], 
                   'loadBy'=>$_POST['loadBy'] );
   if ($params=='')
      { return; }
   foreach ( explode('&',$params) as $p ) {
      $pv = explode('=',$p);
      if ( count($pv)!=2) {
         $msg = "parsePOST ill-formed parameter: $params";
         atrain_log(null,null,null,$msg);
         atrain_exit($msg);
      }
      $_POST[$pv[0]] = html_entity_decode($pv[1]);
   }
}

Rather than modify all the links to add an onclick attribute, it would be better to setup a function to run when the dom is loaded which installs an onclick handler on all the link.  If you only want to target certain links, give them a class that can be used to identify them.  If your using a library such as jQuery then it is a fairly simple task:

 

jQuery(function($){
   $('a').click(function(e){
       e.preventDefault(); //prevents the browser from following the link.
       //generate, populate, and submit form
   });
});

 

Using plain JS would not be much harder but I'll leave that as an exercise for the reader.

 

 

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.