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]);
   }
}

Link to comment
Share on other sites

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.

 

 

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • 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.