In previous lessons we've been looking at client-side scripts, which are programs embedded in the HTML code for a webpage; programs that the browser (web client) executes. In this lesson, we'll look at server-side scripts, which are programs that the web server machine runs in response to something done by a web client (browser).

A first look at a server-side script

A server-side script is a program run on the web-server that generates content (usually HTML) for a web-client or otherwise responds to some web-client action. The simplest server-side script is one that generates HTML content which then gets sent to the browser on the other end. These scripts can be written in a number of languages, including Javascript. Of course we'll use Javascript, since we already know it. We start off by looking at an old familiar example: a script that writes "G O N A V Y !" 1,000 times. We've already done this as a client-side script, now we'll do this as a server-side script. To start off with, look at these links:
  1. ex0.html, client side
  2. ex0.jsx?, server side
  3. ex0.jsx, server side (source)
Note that the link to the script has the "?" at the end, indicating to the server that it's a script to execute and not a file to server. The code for the server-side is almost the same as the client-side. The big difference is: what gets executed where, and what actually gets sent. The following should illustrate the differences:

Client Side
server finds
<html>
<head></head>
<body>
<script type="text/javascript">
  var iter = 0;
  while(iter < 1000)
  {
    document.write("G O N A V Y ! ");  
    iter = iter + 1;
 
  }
</script>
</body>
</html>
, server sends
<html>
<head></head>
<body>
<script type="text/javascript">
  var iter = 0;
  while(iter < 1000)
  {
    document.write("G O N A V Y ! ");  
    iter = iter + 1;
 
  }
</script>
</body>
</html>
, browser executes & renders as

Server Side
server finds & executes
function () {
  var out = "";
  var iter = 0;
  while(iter < 1000)
  {
    out = out + "G O N A V Y ! ";
    iter = iter + 1;
  }
  return out;
}
, server sends
, browser renders as

Now, which version do you think is better for this job of printing GO NAVY! 1,000 times? Why?

Sending data to server-side scripts with forms

Let's consider a very simple interactive web-page that converts a temperature in Fahrenheit into Celsius. We'll look at a client-side version of this and a server-side version, side-by-side.

Client Side Fahrenheit-to-Celsius Converter Server Side Fahrenheit-to-Celsius Converter
°F

(shift+refresh to return)
°F

(browser back-button to return)
<form name="cc" onsubmit="return false;">
  <input type="text" name="fahrenheit"> &#176;F
  <input type="button" value="Convert" 
	 onclick="var f = document.forms.cc.fahrenheit.value;
		  var c = 5/9*(f - 32);
		  document.body.innerHTML = c + ' &#176;C';
		  ">
</form>
<form name="cs" onsubmit="return false;"
	  action="http://rona.cs.usna.edu/~si110/lec/l13/f2c.jsx" 
	  method="get">
  <input type="text" name="fahrenheit"> &#176;F
  <input type="button" onclick="submit()" value="Convert">
</form>

Verify that both work, then try look for differences in how they work from the user's perspective. You should notice that the client-side version keeps you at the same URL. The server-side version, however, takes you to a different URL — and a strange one at that! The server-side URL ends with something like:

f2c.jsx?fahrenheit=45
There are two basic mechanisms for sending arguments (inputs) to server-side scripts: GET and POST. The GET mechanism is simpler and is what we see here. The URL for the script ends with a "?" followed by name=value pairs that give the names and values of the parameters the server-side script will use as inputs. In fact, we don't need the nice fancy web page with the form field and button in order to use this conversion script. Simply enter the URL
http://rona.cs.usna.edu/~si110/lec/l13/f2c.jsx?fahrenheit=78
in your browser's address bar with different values for "fahrenheit" and you can get the conversions directly. Here are a couple of URLs from the wild you can do this with: You should've noticed that multiple arguments (inputs) are separated by &'s.

f2c.jsx
function(fahrenheit) {
   var c = 5/9*(fahrenheit - 32);
   return c + ' &#176;C';
}
The server-side script f2c.jsx is very simple, as you see. In looking at it, don't worry about the function(fahrenheit){ ... } wrapped around the code except to accept that it's there, and to know that you need to list the parameter (input) names, separated by commas if there's more than one, inside the ( )'s in order to access their values within the script. The script ends by returning a string. That string becomes the <body> contents of the HTML code that gets sent to the browser. These server-side scripts can do many things, including read from and write to files sitting on the server. How one would do that with Javascript is way outside the scope of this course and, actually, is dependent on the particular Javascript interpreter you're using. We're using the JSEXT interpreter, in case you'd like to look into this more deeply.

Now, let's turn to the browser's part in a server-side scripted system. We could make use of server-side scripts using only the tools we already know: we could write client-side scripts that build a URL string with the name/value pairs determined by some interaction with the user. However, that's not how it's usually done. Usually server-side scripts are called automatically using a feature of forms we haven't yet discussed: submit. Form elements were actually introduced specifically to get user input and call server-side scripts. There is a DOM function called submit() that automatically grabs the value attribute for each named form input element, and builds the name/value pairs from the names and values of those input elements. The first part of the URL that will be called, i.e. everything before the "?", comes from the form's action attribute. Recall the server-side example's form element was defined like this:

<form name="cs" 
	  action="http://rona.cs.usna.edu/~si110/lec/l13/f2c.jsx" 
	  method="get">
  <input type="text" name="fahrenheit"> &#176;F
  <input type="button" onclick="submit()" value="Convert">
  </form>
Here's how things work:
  1. The user enters a value (say, 78.3) in the fahrenheit text-input.
  2. The user clicks the Convert button.
  3. The button's onclick script is executed, which simply calls the submit() function from the DOM.
  4. The submit function builds a URL as follows (because the form's method attribute is GET):
    http://rona.cs.usna.edu/~si110/lec/l13/f2c.jsx?fahrenheit=78.3
    \____________________________________________/ \________/ \__/
        from the form's "action" attribute          input        input element's
                                                    element's    value
                                                    name	  
  5. The browser sends the above link in a GET request to the server specified in the URL.

Now we are in a position to understand why our client-side only use of forms always included the form attribute definition onsubmit="return false;", it was to stop the browser from trying to form a URL and pull up a new page!

Note: if you hit enter after typing something into the text box, the form is automatically submitted. This can be turned off, but it's a bit of a pain, since Explorer does it differently than the other browsers. One way to do this is to keep the form element's onsubmit="return false;" attribute definition. When our button calls submit(), the form's onsubmit is bypassed.

A silly exercise

Here's a bit of a silly exercise, but one that will show whether or not you've got the mechanism down for all of this: Create a webpage that takes a number from the user and prints that many GONAVY!'s. You should be able to modify existing scripts and webpages to make that work for both client-side and server side.

Question 1: if you choose a big number, which version is faster?

Question 2: why?

The Trap of Client-Side Validation
In an October 2012 blog post, Chris Foster pointed out a vulnerability in a Javascript library called filepicker.io. The vulnerability boils down to this: they use client-side input validation and, as we know, an attacker can bypass client-side validation.

Lots of businesses and individuals are moving to "cloud storage", which means that a big company (like amazon.com) stores your data for you, and you / your company can access the data from anywhere. Filepicker.io is a Javascript library (http://api.filepicker.io/v0/filepicker.js) that you include in your HTML just like we've already done, and it provides easy-to-use functions that allow the website to give users the ability to upload files to cloud storage space owned by the website. Now, the website will be charged more or less money for that cloud storage depending on how many gigabytes of storage they use. For that reason (and others) the site needs to limit the size of files that can be uploaded. Filepicker.io provides that functionality, but checks the file size client-side. In the blog post, Mr. Foster demonstrates that he can send the the same GET requests to cause a file to be uploaded to a site's cloud storage that the filepicker.io library would send from a script that he wrote (a glorified application of netcat). The difference is that, with his script, the client-side validation code is completely bypassed. Thus, he can lie about the file-size when he uploads with his script, and can upload as big a file as he likes to the website's cloud storage ... which could end up costing big money!

Validation / Sanitizing Input

If a user wanted to print 10,000,000 GONAVY!'s in his browser window using a client-side script, that'd be his own business. If a user wanted to do that using a server-side scripted system, on my server, that'd be another matter altogether. It'd be my server that was slowed down processing the script, and all that silly data would be sent out over my network. So I'd like to put a limit, maybe of 5,000, on the size of the number I'd allow my server script to process. This means that I should check the number and refuse the request if it's too big ... or, I suppose, if it's not a valid number. This is called validation (or sometimes we say we're sanitizing the input). There are two places I could do this validation, on the client or on the server.

Let's look at client-side validation first. Your instructor will have a a server-side script for you like this:

function (N) {
  var out = "";
  var iter = 0;
  while(iter < N)
  {
    out = out + "G O N A V Y ! ";
    iter = iter + 1;
  }
  return out;
}
that you can use. It's expecting a URL with a name/value pair for the name N, like this: "?N=800". The webpage should take N, the number of times to print GONAVY!, from the user via forms, and call the server-side script with it. When you have that working, modify the HTML form so it refuses to submit to the server with N > 5,000. Only if N < 5000 should the Javascript attached to the botton's onclick attribute should excute submit(). (Remember to keep the form's onsubmit="return false;" set.

This is client-side validation. What's the problem here? Well, someone who's up to no good can still hammer my server with requests for N=999999999999 because they can always craft the appropriate URL without using the original webpage, thus bypassing my client-side validation. Therefore it's critical to also use server-side validation. In this case. we could do something simple like this:

function (N) {
  if (N > 5000) { N = 0; }
  var out = "";
  var iter = 0;
  while(iter < N)
  {
    out = out + "G O N A V Y ! ";
    iter = iter + 1;
  }
  return out;
}

Extra Example You Can Try

There is a script at
http://rona.cs.usna.edu/~si110/lec/l13/checkers.jsx
that creates a page with a nice checkerboard pattern whose dimensions are given to the script as values named rows and cols.

Try to craft a URL from that information alone to get a page with the checkerboard pattern. [click to show answer]

Next, try to create an html file with a form that allows the user to enter a number of rows and a number of columns and submits them to the script to get the checkerboard pattern. Use one of the examples from above as a starting point. [click to show answer]