Inital commit

This commit is contained in:
Tilman
2011-10-26 10:11:42 +02:00
commit c0da376199
888 changed files with 44367 additions and 0 deletions
@@ -0,0 +1,304 @@
// Netzprogrammierung
// Gruppe 01 (Übung 1)
// Aufgabe 1-4
/*
ProxyServer.java
Anmerkungen:
- Dem Proxyserver können auf der Kommandozeile optional Port und Debug Level als int-Werte
übergeben werden (Silent Mode, nur Header, etc.). Als default werden Port 10000 und Debug
Level 3 genutzt.
Konzepte:
- Die Eingabeströme von Client und v.a. Server werden über binäre Inputstreams abgewickelt,
um Bilder und andere Binärdaten zu erhalten
- Aus dem Client-Request werden Server und Port geparst, so kann bspw. auch http über Port
8080 abgefragt werden
- Der vom Client entgegengenommene Header wird teilweise bereinigt, da er sich an einen
Proxy richtet (Zeile 148 ff.)
- Die Antwort vom Server wird über die private Methode readLine() (Z. 242 ff.) abgewickelt, so
kann der InputStream komfortabel gehandhabt werden
- Die empfangenen Headerzeilen werden aufsummiert und durch die angeforderten Ressourcen
geteilt. Das Ergebnis wird über den Header an den Client gesendet (Z. 190 ff.)
- Die meisten Exceptions werden nur abgefangen, der Proxyserver läuft danach wieder an, da
die meisten Fehler durch Abbruch der Verbindung durch den Client u.ä. entstehen, bemerkt
man dies im Betrieb i.d.R. nicht
- Die einzige gesondert behandelte Exception ist die Connection Exception (Z. 214): Tritt sie
auf, wird HTTP-Fehlercode 500 an den Client übermittelt
*/
package uebung01.aufgabe04;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.ConnectException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Iterator;
import java.util.LinkedList;
/**
* Ein einfacher Proxy-Server, der die durchschnittliche Anzahl empfangener Headerzeilen ermittelt.
*
* @author Tilman Walther
*/
public class ProxyServer {
// da unser einfacher Proxy die content-length nicht beruecksichtigt (die
// auch nicht von jedem Server gesendet wird), muessen Verbindungen oft
// per Timeout beendet werden.
final int SERVER_TIMEOUT = 2500;
// da Java den Linefeed dem System anpasst, nutzen wir einen
// String, der sich nach dem HTTP-Protokoll richtet
final String LF = new String(""+((char) 13)+((char) 10));
long headerLineCount = 0;
long itemCount = 0;
StringBuffer lineBuffer = new StringBuffer(600);
public ProxyServer(int port, int message) throws IOException {
System.out.println("PROXY: Starting ProxyServer on port "+port);
ServerSocket proxySocket = new ServerSocket(port);
Socket client;
BufferedInputStream clientIn;
PrintStream clientOut;
Socket server;
BufferedInputStream serverIn;
PrintStream serverOut;
String request;
String domain;
int serverport;
LinkedList requestStrings = new LinkedList();
String s;
byte[] buffer = new byte[1024];
int in1;
long headerLineAverage;
while (true) {
if (message > 1) System.out.println("PROXY: Listening... (press Ctrl+C to end)");
client = proxySocket.accept();
clientIn = new BufferedInputStream(client.getInputStream());
clientOut = new PrintStream(client.getOutputStream(), true);
try {
// Anfrage vom Browser holen
s = readLine(clientIn);
// Ressource extrahieren
request = s.substring(0, s.indexOf(" ")+1) + s.substring(s.indexOf("/", s.indexOf("//")+2));
// Domain und Port extrahieren
domain = s.substring(s.indexOf("//")+2);
domain = domain.substring(0, domain.indexOf("/"));
if ((in1 = domain.indexOf((int) ':')) > -1 ) {
serverport = Integer.parseInt(domain.substring(in1+1));
domain = domain.substring(0, in1);
}
else {
serverport = 80;
}
if (message > 1) System.out.print("PROXY: Request from client: "+s);
// Restlichen Anfrage-Header holen
requestStrings.clear();
do {
s = readLine(clientIn);
requestStrings.add(s);
if (message > 4) System.out.print(" "+s);
} while (!s.equals(LF));
long time = System.currentTimeMillis();
try {
if (message > 1) System.out.println("PROXY: Connecting server "+domain+":"+serverport);
server = new Socket(domain, serverport);
server.setSoTimeout(SERVER_TIMEOUT);
serverIn = new BufferedInputStream(server.getInputStream());
serverOut = new PrintStream(server.getOutputStream(), true);
if (message > 1) System.out.print("PROXY: Sending request to server: "+request);
serverOut.print(request);
// Angepassten Header an Server schicken
Iterator iter = requestStrings.iterator();
while (iter.hasNext()) {
s = (String) iter.next();
if (s.startsWith("Proxy-Connection")) {
serverOut.print("Connection: close"+LF);
if (message > 2) System.out.print(" Connection: close"+LF);
}
else if (s.startsWith("Transfer-Encoding")) {
serverOut.print("Transfer-Encoding: identity"+LF);
if (message > 2) System.out.print(" Transfer-Encoding: identity"+LF);
}
else if (s.startsWith("Accept-Encoding")) {
s = s.substring(0,(s.length()-2)).concat(",identity"+LF);
//s = "Accept-Encoding: identity"+LF;
serverOut.print(s);
if (message > 2) System.out.print(" "+s);
}
else {
serverOut.print(s);
if (message > 2) System.out.print(" "+s);
}
}
// Antwort vom Server entgegennehmen
try {
// Header empfangen
s = readLine(serverIn);
// --> Hier koennen HTTP response codes abgefangen werden
if (message > 1) System.out.print("PROXY: Receiving data from server: "+s);
itemCount++;
while (!s.equals(LF)) {
headerLineCount++;
if (message > 2) System.out.print(" "+s);
clientOut.print(s);
s = readLine(serverIn);
}
// durchschnittliche Anzahl der Headerzeilen berechnen
headerLineAverage = headerLineCount / itemCount;
if (message > 2) System.out.print(" X-mean-headercount: "+ headerLineAverage + LF + LF);
clientOut.print("X-mean-headercount: "+ headerLineAverage + LF + LF);
// Daten empfangen
while ((in1 = serverIn.read(buffer)) > 0) {
if (message > 3) System.out.write(buffer, 0, in1);
clientOut.write(buffer, 0, in1);
}
}
catch (SocketTimeoutException ste) {
if (message > 1) System.err.println("PROXY: Connection timed out");
}
if (message > 1) System.out.println("PROXY: Time "+(System.currentTimeMillis()-time)+" ms");
if (message > 1) System.out.println("PROXY: Unconnect...\n");
serverIn.close();
serverOut.close();
server.close();
}
catch (ConnectException ce) {
if (message > 0) System.err.println("ConnectException, sending code 500 to client");
buffer = ("HTTP/1.0 500\nContent Type: text/plain\n\nError while connecting server: "+domain+"\n").getBytes();
clientOut.write(buffer, 0, ("HTTP/1.0 500\nContent Type: text/plain\n\nError while connecting server: "+domain+"\n").length());
}
clientIn.close();
clientOut.close();
client.close();
}
catch (SocketException se) {
if (message > 4) System.err.println("SocketException");
}
catch (Exception e) {
// nothing, just try again
if (message > 4) e.printStackTrace();
}
}
//proxySocket.close();
}
/**
* Liest eine Zeile vom binären Eingabestrom.
* (Auf diese Weise bleiben binäre Daten korrekt erhalten.)
*/
private String readLine(InputStream in) throws IOException
{
int i;
lineBuffer.setLength(0);
while (((i = in.read()) > 0) && (i != 13)){
lineBuffer.append((char) i);
}
// nach HTTP 1.1 müssten die Zeilenenden mit #13#10 markiert sein
// (durch die Aufteilung schlucken wir auch Unix/Macintosh)
if (i == 13) {
lineBuffer.append((char) 13);
in.mark(1);
if (in.read() != 10)
in.reset();
else
lineBuffer.append((char) 10);
}
return lineBuffer.toString();
}
public static void main(String[] args) throws IOException {
int port = 10000; // default port
int message = 3; // default output level
if (args.length > 2) {
System.out.println("usage: MultServer [port number] [output level]");
}
else {
if (args.length > 0) {
try {
port = Integer.parseInt(args[0]);
}
catch (NumberFormatException nfe) {
System.out.println(args[0]+" is not a valid port number.\nusage: MultServer [port number] [output level]");
System.exit(1);
}
}
if (args.length > 1) {
try {
port = Integer.parseInt(args[1]);
}
catch (NumberFormatException nfe) {
System.out.println(args[0]+" is not a valid port number.\nusage: MultServer [port number] [output level]");
System.exit(1);
}
}
}
new ProxyServer(port, message);
}
}