Rechnernetze / Kommunikationssysteme

Praktikumsversuch HTTP-Protokoll

Ziel

Sie erhalten in tiefes Verständnis für HTTP, indem Sie dieses nutzen und analysieren.

Übersicht

Sie experimentieren mit diesem Protokoll per Konsole und außerdem nutzen Sie Java. Sie sollen einen Client in Java schreiben, welcher eine bestimmte Webseite per HTTP-Request von einem Server holt und auf der Konsole unformatiert (als html-Code) anzeigt. Nutzen Sie Linux auf dem Praktikumsrechner falls Sie im HTW-Labor arbeiten. Zuhause können Sie ein beliebiges Betriebssystem mit Javaunterstützung nutzen. Sehen Sie sich die Folien zum HTTP-Protokoll und zu den Sockets an (Folien Sockets und Folien Anwendungsschicht).

HTTP ist ein Protokoll nach dem Request-Response-Prinzip. In klassischen Webservern genutzte Request-Methoden sind: OPTIONS, HEAD, GET, POST. Für REST-Webservices werden weiterhin PUT, DELETE, PATCH genutzt. Das Netzwerkprotokoll WebDAV nutzt weitere Methoden.

Folgende Headertypen werden verwendet (Auswahl an Attributen):

Response Codes

Wichtige Response-Codes sind:

Content Negotiation

Ein wesentlicher Bestandteil von HTTP ist die Inhaltsvereinbarung (Content-Negotiation). Diese kann Server-driven oder Agent-driven sein. Bei Agent-driven sendet der Server bei Mehrdeutigkeiten eine Liste mit möglichen Parametern und entsprechenden URLs. Der Agent wählt dann aus dieser Liste aus.

Server-Driven Content Negotiation

Der Server wählt die gewünschte Ressource, basierend auf den Accept-Headern der Clients. Wenn die Bedingung nicht erfüllt werden kann, wird Code 406 gesendet. Sendet der Client keinen Accept-Header, wird die Standard-Ressource gesendet.

Agent-Driven Content Negotiation

Diese Form wird manchmal bei einer REST-API eingesetzt. Beispiel:

GET /resource HTTP/1.1

HTTP/1.1 300 Multiple Choices 
Content-Type: application/vnd.api+json

{
    "available_formats": [
      {"type": "application/json", "url": "/resource.json"},
      {"type": "application/xml", "url": "/resource.xml"}
    ]
}

GET /resource.json HTTP/1.1

Beispiele:

Client:

Server:

HTTP-Ping

Neben der Nutzung des ICMP-Protokolls für die Prüfung einer Verbindung, kann auch direkt die Verbindung zu einem Webserver getestet werden. Das Komandozeilentool httping kann z.B. hierfür verwendet werden. I.d.R. wird der Test mittels eines HEAD-Requests erfolgen.

Machen Sie sich mit diesem Tool vertraut (z.B. mittels man-Page) und testen Sie die Verbindung zu verschiedenen Webservern per HTTP und HTTPS.

HTTP mittels Telnet

Als Beispiel soll die Startseite einer Website aufgerufen werden. Das HTTP-Protokoll kann auch mittels einer Telnet-Verbindung manuell genutzt werden. Überlegen Sie sich die dazu erforderlichen Schritte und geben Sie diese in der Konsole ein. Beachten Sie, dass Sie für Telnet den Port des gewünschten Anwendungsprotokolls (HTTP) angeben. Nutzen Sie für die Ermittlung eines minimalen HTTP-GET-Request die RFC für HTTP/1.1 (RFC 2616, Abschnitt 5).

Prüfen Sie beim Erhalt der Antwort bei welchem Teil es sich um den HTTP-Response (Headerzeilen) und bei welcher Teil es sich um die eigentlichen Daten (Payload) handelt. Nehmen Sie zum Testen die Website: http://checkip.dyndns.org oder http://www.informatik.htw-dresden.de. Beachten Sie, dass das Verfahren mittels Telnet nur für die unverschlüsselte Übertragung (kein https) funktioniert. Je nach Timeouteinstellung des jeweiligen HTTP-Servers haben Sie nur begrenzt Zeit (ca. 10 - 300 s) für die Eingabe. Beachten Sie, dass Sie nach der letzen Zeile zweimal die Entertaste betätigen müssen und die notwendige Leerzeile zu erzeugen. Bestimmen Sie den Timeout des Servers. Bei einem korrekten Ablauf würden folgende Informationen dargestellt.

telnet 
set crlf
open checkip.dyndns.org 80
Trying 216.146.38.70...
Connected to checkip.dyndns.com.
Escape character is '^]'.
GET / HTTP/1.1
Host: dyndns.org

HTTP/1.1 200 OK
Content-Type: text/html
Server: DynDNS-CheckIP/1.0
Connection: close
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 105

<html><head><title>Current IP Check</title></head><body>Current IP Address: 141.56.131.71</body></html>
...
Connection closed by foreign host.

Probieren Sie auch andere Request-Methoden aus (HEAD, OPTIONS).

HTTPS mittels OpenSSL

Um Websites zu testen, die ausschließlich HTTPS nutzen, ist ein Werkzeug mit TLS-Unterstützung notwendig. Dabei ist zu beachten, dass Webserver i.d.R. den standardisierten Zeilenabschluss (CR+LF) für Kommandos fordern. Im Praktikum nutzen wir OpenSSL, die Nutzung ist möglich mittels des Aufrufs: openssl s_client -crlf -connect domain:port Testen Sie diverse Websites, z. B. (www.heise.de). Versuchen Sie, die Startseite der HTW-Dresden zu empfangen. Nachfolgend ist ein Beispiel dargestellt:

openssl s_client -crlf -connect www.heise.de:https
GET / HTTP/1.1
Host: www.heise.de

HTTP/1.1 200 OK
Server: nginx
Date: Mon, 30 Mar 2020 16:05:48 GMT
Content-Type: text/html; charset=UTF-8
Last-Modified: Mon, 30 Mar 2020 16:05:48 GMT
Cache-Control: public, max-age=30
Age: 20
Strict-Transport-Security: max-age=15768000
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Vary: Accept-Encoding,X-Export-Format,X-Export-Agent
Accept-Ranges: bytes
Content-Length: 513971
Connection: keep-alive

<!DOCTYPE html>
<html
...

HTTP/HTTPS-Client mittels Curl

Mittels des Konsolenprogramms Curl können Sie testen, ob ein Webserver HTTP/2.0 unterstützt:

curl --http2 -sI https://www.htw-dresden.de

Bei einer erfolgreichen Verbindung ist HTTP/2 200 zu sehen. Mittels man curl können Sie die Parameter in Erfahrung bringen.

Wichtige CURL-Optionen:

Simuliere Browser:

curl -X GET \
  -H "User-Agent: Chrome/63.0.1 Safari/534.3" \
  -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" \
  -H "Accept-Language: de-DE,de,en-US,en;q=0.9" \
  -H "Referer: https://www.example.com" \
  -H "Connection: keep-alive" \
  https://example.com/resource

Zum Experimentieren mit per HTTP übertragenen Formulardaten können Sie die URL https://www.informatik.htw-dresden.de/~jvogt/it1/formdemo/form.php nutzen, welche die GET- und POST-Variablen zurückgibt. Probieren Sie beide Varianten mit jeweils 2 Variablen aus!

Probieren Sie weitere Request-Methoden aus. Was können Sie mit curl noch alles anfangen?

HTTP/HTTPS mittels Java

Nachdem Sie das HTTP-Protokoll über Telnet genutzt haben, können Sie beginnen, das Protokoll in einem Java-Programm als HTTP-Client zu nutzen.

Als Editoren stehen z.B. vim, gedit, kate oder die Entwicklungsumgebungen Eclipse bzw. IntelliJ zur Verfügung. Ein Javaprogramm muss mit der Endung .java abgespeichert werden. Der Dateiname muss dabei identisch mit dem Klassennamen sein (inklusive Groß- und Kleinschreibung).

HTTP

Die Schritte im Programm gliedern sich wie folgt:

  1. TCP-Socket zum entsprechenden Server öffnen (es ist sinnvoll, die Serveradresse über die Kommandozeile zu übergeben)
  2. Einen HTTP-Request als String anlegen
  3. diesem String über das Socket senden
  4. die Antwort als String iterativ aus dem Socket auslesen und auf der Konsole ausgeben
  5. der Server wird nach einem Timeout die Verbindung schließen und das Clientprogramm wird sich beenden

Folgendes ist zu beachten:

Sie können das nachfolgende Listing hierfür nutzen und müssen nur den Requeststring definieren. Ermitteln Sie vorab die Funktionsweise des Programms

import java.io.*;
import java.net.*;
import javax.net.ssl.*;
public class WGet_simple {
  public static Socket clientSocket = null;
  public static String targethost, targetfile;
  public static int targetport;
  public static String request, req1, req2, res, nl;
  public static void main(String[] args) {
    if (args.length < 3) {
      System.out.println("Aufruf: java WGet_simple host port pfad");
      System.exit(-1);
    }
    targethost = args[0]; // url-host
    targetport = Integer.parseInt(args[1]); // url-port
    targetpath = args[2]; // url-path
    try {
      // TCP-Socket (unverschlüsselt)
      clientSocket = new Socket( targethost, targetport );
      // alternativ TLS-Socket (verschlüsselt)
      //SSLSocketFactory sslFact = (SSLSocketFactory) SSLSocketFactory.getDefault();
      //clientSocket = (SSLSocket) sslFact.createSocket( targethost, targetport );
      // Bietet formatierte Textausgabe u.a. println()
      PrintWriter clientOut = new PrintWriter(new BufferedOutputStream( clientSocket.getOutputStream()) );
      BufferedReader clientIn = new BufferedReader(new InputStreamReader( clientSocket.getInputStream() ));
      //TODO
      nl = ""; // new line definition for internet protocols
      req1 = ""; // request line 1
      req2 = ""; // request line 2
      request = ""; // total request string to send over TCP-connection
      System.out.println("HTTP-Request-Header:\n-------------------");
      System.out.println(request + System.lineSeparator() );
      // Sende Request + Leerzeile über TCP-Stream
      clientOut.print( request );
      clientOut.flush();
      System.out.println("HTTP-Response-Header:\n-------------------");
      while ( !(res = clientIn.readLine()).equals("") ) {
        System.out.println( res );
      }
      System.out.println("\nHTTP-Daten:\n----------------");
      while ((res = clientIn.readLine()) != null) {
        System.out.println(res);
      }
      System.out.println("\n------\nVerbindung vom Server beendet");
      clientSocket.close();
    }
    catch (IOException ex){ System.out.println(ex);}
  }
}

Nutzen Sie das Programm, um mit einem POST-Request die Variablen “a=1&b=2” per Header: application/x-www-form-urlencoded an den o.g. Server zu versenden.

HTTPS

Normalerweise könnte man für die Nutzung von HTTP in Java spezielle Klassen verwenden, die die Kommunikation deutlich vereinfachen, z. B. HttpUrlConnection. Hier wollen wir aber nur die grundlegende Funktionalität auf Socketebene testen. Da die meisten Websites mittlerweile ausschließlich mittels SSL/TLS nutzbar sind, werden wir dieses direkt nutzen. Als Startpunkt wählen wir das Listung für HTTP und wählen das TLS-Socket.

Optional

Literatur

Fakultativ


Letzte Änderung: 26. March 2025 19:33