Yaerox has asked for the wisdom of the Perl Monks concerning the following question:

Hey everyone. First of all I need to say sorry for non workable scripts. I'm facing a weird problem on a website I coded. I can't post a workable script because developing a test-script would take a lot of time beside the fact, that I'm working the same way on many many different websites and I'm only facing this problem at one point on one website.

First of all I'll try to describe the way I work. I got a homepage where you can generate order notices. So I got a perl-cgi-script which is printing a webform. If you send this webform, a script - let's call it work.pl - is called. This script is doing stuff on a database.

Coming closer to the problem now ... I connect to my database and do some SELECT to check, if a datarow with the etnered number does already exist like this pseudo-code:
my $iNumber; prepare("SELECT number FROM table WHERE number = $iEnteredNumber") ( $iNumber ) = fetchrow_array(); finish(); if ( defined( $iNumber ) ){ redirect("error.pl"); exit; } #more stuff done here redirect("success.pl");
This is working fine on Chrome and Firefox. I never could force an mistake on both browsers here. If I now use the IE (latest version and updates - Version: 11.0.9600.17914, Updateversion: 11.0.21) it behaves different sometimes.

Example: I enter Number 2 and send the form. Ask the database if a row with the value 2 in a specific column exist. If it does, my if-clause should redirect to error.pl and exit the script. If it does not, the script should follow more instructions on the #do more stuff aprt and later redirect to the success.pl page.

Sometimes, it does work like it should, but even sometimes it tells me a row with the number X already exists but it definetaly does not at the point on the script! On the #do more stuff here part the row with the number entered would be inserted into database. Now I got the weird behaviour like already said, plus the exit is getting ignored. So even if the if-clause matches and I redirect the row is getting inserted into database later on #do more stuff ... another third weird way the script runs sometimes is, that the line is getting inserted 2 times ... all happens sporadic and I can't 100% reproduce it. No loops on this point!

My first thoughts was:
- redirection loop
- wrong if-clause due to the datatype of the variables (the data type on the db is NUMBER - working with oracle)

I'm clueless, what the hell is going on here ... I did some print debugging and this always behaves the same: if I entered a number, which isn't in my DB now, the print $iNumber should be empty, but in real it is the exact same number I entered. So in this case if clause always matches like it should. But why the script ignores the exit tho and still do the rest of the script? Imo browsers can't infect the way apache is working, or am I wrong?

Anyway, even debugging with the developer tools in browsers won't help me right now to see if I got a redirection loop, or what is going on. Apache error-log is clean, I'm now take a look on access-log to check redirection-loop on aother way.

Please let me know if something sounds wrong, or if you need some more explanaitions. I'll do my best to give you as many information you need...

So far, thanks in advice.

Update:
I just looked into my apache-access.log and found out that it seems to seriously getting called 2 times. Then god knocked on my brain, remembering me I submit the form using javascript...

<form action="myscript.pl"...> ... </form> ... <script> function js_submit(){ if ( validInput() == true ){ document.getElementById('myform').submit(); return true; } else { return false; } } </script>
I removed  return true; and it seems to work. I'm not sure yet, and I really need to make 100% sure this is the mistake, so I'm on this. So far thank you. If you got any pros/cons if this could be what's wrong or not, feel free to let me know.

Replies are listed 'Best First'.
Re: Weird CGI behaviour on different Browsers - Apache
by Corion (Patriarch) on Aug 04, 2015 at 12:19 UTC

    I can think of two very annoying places where state gets kept that is out of your control:

    1. You're using mod_perl and somewhere you keep state in variables. This might be the proverbial global $counter variable or something more hidden. Usually contributing to the confusion is if you have multiple Apache processes (and mod_perl interpreter instances) where each process keeps its own state. The approach to the solution is to start Apache in the single-worker mode and to try to reproduce the failure there.
    2. Browser caching is the second nasty thing that shows you results that you don't expect. I usually use wget or curl or LWP::Simple to get at the raw data without any browser caching getting in the way.

    As a general approach, I would add the appropriate indices on the database side, making the number column unique to prevent duplicate entries even if the application logic fails.

      1. No I don't use mod_perl, good point, I should have mentioned this.

      2. Good idea, I'll keep that in mind for debuggings later on ...

      Using a primary key would help to get a good database state, I think I'll do this for future purposses too, but I really need to know for sure, the reason for this. For me solving problems is still a must do, even if I found a way to prevent things to go wrong. Thanks for the tip.

        As soon as you add the constraint to the database, the moment where the double insert happens will be shown in your server logs. This makes debugging things easier in my experience.

Re: Weird CGI behaviour on different Browsers - Apache
by anonymized user 468275 (Curate) on Aug 04, 2015 at 11:55 UTC
    <subliminal_whisper>

    Go on, withdraw support for IE, you know you want to do it ;)

    </subliminal_whisper>

    One world, one people

      Nothing more would make me happier. Unfortunately, it's not my decision ;)
Re: Weird CGI behaviour on different Browsers - Apache
by Anonymous Monk on Aug 04, 2015 at 12:10 UTC

    Multiple inserts of the same value should probably be a huge red flag: sounds like you're not keeping track of your state properly, so you should start doing that - are you using some kind of web framework, or plain vanilla CGI? Why do you need to bounce the user around between different scripts anyway, why can't you handle what "success.pl" and "error.pl" do in the same script?

      What do you think and mean by saying "Multiple inserts of the same value"? I wanna make sure we're talking about the same thing. In my script, I only do the INSERT if the script doesn't stop after redirecting in my if-clause. Basically there are no multiple inserts...

      No frameworks, just perl and cgi. With perl I also print some javascript, and I do this always like this: print qq{<!--My HTML HERE-->};.

      Why do I need to bounce the user around? Well I got a HTML-Form, and if I send the form something needs to get done in the background. So do I have a choice in not doing this?
      Update: I just missed to say, that if it is successfully, I need to show him the created order notice. The user is also able to look other already created ones, so I have one script always having the same function. Same for error.pl, I'm always redirecting to error.pl using different parameters to print different errors. For me this makes it a little bit cleaner on developing and maintaining.
      Thank you sir.
        What do you think and mean by saying "Multiple inserts of the same value"?

        You said in the OP:

        ... another third weird way the script runs sometimes is, that the line is getting inserted 2 times ...

        Which I took to mean that the INSERT is executed twice and you end up with two rows in the DB with the same value(s)...?

Re: Weird CGI behaviour on different Browsers - Apache
by Anonymous Monk on Aug 04, 2015 at 13:27 UTC
    Update: ... If you got any pros/cons if this could be what's wrong or not, feel free to let me know.

    In addition you should disable the submit button to prevent double clicks, and definitely still introduce constraints on your database.

      I'm thinking about that, but this decision shouldn't be in a rush because my real database table logically allowes to have dublicated numbers because the type is different. Type is order notice or bill. I'll just let this here, but I'm seriously thinking about it. Thanks.

        A constraint can span more than one column. You need to think about this long from a business perspective, but if you are certain that the combination (number, type) needs to be unique, you can create a constraint or a unique index for that.

        A better database design would be to have your orders and invoices in separate tables with customers in a third. It may or may not relate to your problem, but it is clearer, less error-prone, probably more efficient, easier to debug, and way easier to develop code for.

        The way forward always starts with a minimal test.