Web Applications
How a search web application works end to end: a socket server speaking HTTP, HTML/CSS pages with forms, JavaScript that updates the DOM with fetched JSON, URL and character encoding, and protection against code injection and cross-origin abuse.
Concepts#
- Network Sockettransport layer: host + port endpoints, bind/listen/accept, reading bytes in rounds start here
- Character Encodingsockets carry bytes, code uses strings: encode/decode explicitly (UTF-8)
-
HTTP Protocolrequest line, status line, headers (
Content-Length,Content-Typemedia types), status codes -
HTTP Serverthe server loop: read until
\r\n\r\n, parse the path, serve file/template/JSON safely - HTML Structurepage skeleton, key tags, CSS, where scripts go
-
HTML Formstatic app: browser sends
?name=valueand loads a new page; template variables -
URL Encodingescaping query parameters as
%-encoded UTF-8 bytes,+for space - DOM Manipulationdynamic app: select elements, read/write content, event handlers
-
AJAX and Fetch API
fetch+async/await/then+ JSON, no page reload - Code Injection Protectionuntrusted input inserted as HTML executes; use text insertion or sanitize
- Same-Origin Policyscripts may only use results from the page’s own origin unless CORS allows it
How it fits together#
The stack, bottom to top#
browser ──TCP socket (bytes)──► server socket Network Socket
"GET /search.html?query=b%C3%A4r HTTP/1.1" HTTP Protocol + URL Encoding
read until \r\n\r\n, HTTP Server
decode UTF-8, parse, Character Encoding
compute, encode
◄── "HTTP/1.1 200 OK / Content-Type / ... "
renders HTML + CSS HTML Structure
user action → form submit (new page) or JS fetch (DOM update)
Each layer only adds structure to the one below: the socket knows only bytes, HTTP gives them a request/response shape, HTML gives the content a page structure, JavaScript makes the page change without reloading.
Static vs. dynamic web app#
| Static app (Sheet 9, VL09) | Dynamic app (Sheet 10, VL10) | |
|---|---|---|
| Trigger | click on submit button | each keystroke (input/keyup event) |
| Who sends the request | the browser, via form | JavaScript, via fetch |
| Request | GET /search.html?query=… HTTP/1.1 | GET /api/search?query=… HTTP/1.1 |
| Server builds | whole page: search.html with %QUERY%/%RESULT% substituted | only data: JSON (application/json) |
| Browser shows | new page (full reload) | same page, one element rewritten via DOM |
| Injection risk | template substitution on the server | innerHTML in the client |
Encoding at every boundary#
A query like bär crosses four representations: the string in the input field → URL-encoded UTF-8 bytes in the request line (b%C3%A4r, URL Encoding) → bytes received by the server, URL-decoded and then decoded as UTF-8 to the string bär (Character Encoding) → result string encoded to UTF-8 bytes, whose byte count is the Content-Length. Typical bugs: decoding %XX codes one by one into characters (bär), computing Content-Length from the string length, a <meta charset> that does not match the file.
Three kinds of vulnerabilities#
| Vulnerability | Example | Fix | Note |
|---|---|---|---|
| Access to private data | http://tura:8888//etc/passwd | serve only a whitelist; 403/404 otherwise | HTTP Server |
| Execution of injected code | <script> in a search box, link or forum post | .textContent instead of .innerHTML, sanitize, escape templates | Code Injection Protection |
| Trusted information to an untrusted site | evil look-alike bank site using your session | browser enforces the SOP; servers opt in with Access-Control-Allow-Origin | Same-Origin Policy |
Exam recipe#
- HTML: full skeleton
<html><head>…</head><body>…</body></html>; give every element the script touches anid; include the script withdeferin the head or at the end of the body; for form tasks give the input aname. - JavaScript: select with
querySelector("#id"), attachonclick/addEventListener("input", …), build the URL by concatenation,await fetch(url).then(r => r.json())inside anasyncfunction, write with.textContent(or sanitize if the task mentions injection). - HTTP lines: request line = method + path-with-query (no host) +
HTTP/1.1; response =HTTP/1.1 200 OKandContent-Type: application/json(ortext/htmlfor a page). - Encoding: code point → byte count from the range → fill payload bits → hex →
%XXper byte.
Exercises & Exam Questions#
SuccessSolution
<html><body>
<h1>Search</h1>
<form>
<input type="text" name="query">
<input type="submit" value="Search">
</form>
</body></html>
Since no method is specified, the default is GET. The form data is appended as query parameters:
GET /search.html?query=example HTTP/1.1
SuccessSolution
HTML:
<html><body>
<h1>Enter Query</h1>
<input type="text" id="query"/>
<p id="result"></p>
<button>Predict</button>
<script src="script.js"></script>
</body></html>
script.js:
document.querySelector("button").onclick = async function() {
let q = document.querySelector("#query").value;
let ob = await fetch("/backend?q=" + q).then(r => r.json());
document.querySelector("#result").textContent =
ob.class + " " + ob.probability;
};
The official solution writes with .innerHTML; .textContent is the safer equivalent (Code Injection Protection).
SuccessSolution
Request: GET /?query=bla HTTP/1.1 (the official solution uses the path /api?query=bla; the path depends on the URL chosen in T3.2)
Response:
HTTP/1.1 200 OK
Content-Type: application/json
SuccessSolution
(Not in the exam transcription; derived from the lecture material.)
<html><body>
<input type="text" id="query"/>
<div id="result"></div>
<script src="jquery.js"></script>
<script src="search.js"></script>
</body></html>
Each keyup sends one request to www.gugel.de, port 8888. Request lines GET /?q=h HTTP/1.1 etc.; first fifteen characters:
GET /?q=h HTTP/
GET /?q=he HTTP
GET /?q=hey HTT
SuccessSolution
def search_server(server_socket, index, titles):
while True:
client = server_socket.accept()
request = client.read()
request = request[5 : request.find("HTTP")]
query = request.split(" ")
title = search(query, index, titles)
headers = "Content-Type: text/plain\r\n" + \
"Content-Length: " + len(title) + "\r\n" + \
"\r\n"
client.send(headers + title)
Key ideas: accept in an infinite loop, take the path between GET / and HTTP, split it into keywords, answer with Content-Type, Content-Length, empty line, body.
Corrections to the transcribed solution: the method is receive, not read; len(title) must be converted with str(...); the status line HTTP/1.1 200 OK\r\n is required by the task and missing; request.find(" HTTP") avoids a trailing space in the last keyword; keywords in a URL would be separated by + or %20, not by spaces, so a robust solution splits the URL-decoded path (HTTP Server).
SuccessSolution
document.querySelector("#query").addEventListener("input", async function() {
const content = document.querySelector("#query").value;
const response = await fetch(
"http://localhost:8000/?query=" + content
).then(response => response.text());
document.querySelector("#result").innerHTML = response;
});
defer guarantees the elements exist; "input" fires on every change; .text() because the response is plain text. .textContent instead of .innerHTML would also protect against injection.
Occurrences#
| Exam | Task | Points | Subtopics |
|---|---|---|---|
| DBIS Exam WS1516 (not published) | T3 | 20 | HTML for jQuery, GET request format, UTF-8 byte count, URL encoding |
| DBIS Exam WS1617 (not published) | T3 | 20 | HTML + jQuery conversion tool, UTF-8 encoding of Euro sign |
| DBIS Exam WS1819 (not published) | T4 | 20 | Search function + HTTP server implementation |
| DBIS Exam WS1920 (not published) | T3 | 25 | HTML + CSS + JS with code injection protection, HTTP lines |
| DBIS Exam WS2122 (not published) | T4 | 15 | HTML for “Hardle” game + JavaScript with fetch/jQuery |
| DBIS Exam WS2223 (not published) | T4 | 10 | HTML + script.js for Naive Bayes prediction UI |
| DBIS Exam WS2324 (not published) | T4 | 7 | HTML form, HTTP request line |
| DBIS Exam WS2324-2 (not published) | T4.2–4.3 | 15 | UTF-8 validity / URL encoding (true/false), fetch on each keystroke |
Lectures#
- DBIS_VL09 — sockets, bytes vs. strings, HTTP, media types, HTML, CSS, forms, template variables, URL encoding (static app)
- DBIS_VL10 — JavaScript, DOM,
fetch/async/promises/JSON, multi-threaded server, vulnerabilities (private data, code injection, SOP/CORS), Unicode/UTF-8 and URL encoding (dynamic app)
Related Topics#
- Fuzzy Search and Q-Grams — the web app of Sheets 9/10 serves fuzzy prefix matches for Wikidata entities; the server keeps the Q-Gram Index in memory and answers each request from it (Slides 10).
- SPARQL and Knowledge Graphs — clicking a matched entity shows all triples with it as subject, computed with the SPARQL-to-SQL engine from Sheet 6 (optional in DBIS Sheet 09 (not published), required in DBIS Sheet 10 (not published)).
- Encodings and Compression — UTF-8 in detail (code points, validity, byte counts); URL encoding builds on it.