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).
"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:
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 |
|
| Client Side Fahrenheit-to-Celsius Converter | Server Side Fahrenheit-to-Celsius Converter |
|
(shift+refresh to return) |
(browser back-button to return) |
<form name="cc" onsubmit="return false;"> <input type="text" name="fahrenheit"> °F <input type="button" value="Convert" onclick="var f = document.forms.cc.fahrenheit.value; var c = 5/9*(f - 32); document.body.innerHTML = c + ' °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"> °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=45There 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=78in 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:
http://zipinfo.com/cgi-local/zipsrch.exe?zip=21401&Go=GoChange the zip code to whatever you like, and the page will tell you the community it belongs to.
http://forecast.weather.gov/MapClick.php?CityName=Annapolis&state=MD&site=LWX&textField1=38.9716&textField2=-76.503&e=1textField1 and textField2 are lat/long coordinates for the map on the page. You can change those and change what the map shows you. Try small changes first.
f2c.jsx |
function(fahrenheit) {
var c = 5/9*(fahrenheit - 32);
return c + ' °C';
} |
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"> °F <input type="button" onclick="submit()" value="Convert"> </form>Here's how things work:
fahrenheit
text-input.Convert button.onclick script is executed,
which simply calls the submit() function from
the DOM.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
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.
Question 1: if you choose a big number, which version is faster?
Question 2: why?
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!
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;
}
http://rona.cs.usna.edu/~si110/lec/l13/checkers.jsxthat 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]
http://rona.cs.usna.edu/~si110/lec/l13/checkers.jsx?rows=10&cols=20
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]
<html>
<body>
<form name="checkers"
action="http://rona.cs.usna.edu/~si110/lec/l13/checkers.jsx"
onsubmit="return false;">
Number of rows: <input type="text" name="rows"><br>
Number of columns: <input type="text" name="cols"><br>
<input type="button"
value="Get Checkerboard Pattern"
onclick = "submit();">
</form>
</body>
</html>