# Post u Head Request an Server



## Nummer6800 (23. Nov 2016)

Hallo.

Client kontaktiert also Server. Client setzt Post oder Head Kommando ein. Server unterstuetzt die Befehle nicht. Gibt also passende 501 Fehlermeldung aus.

Hier der Server Code.

"Wenn mit 501 geantwortet wird, so sollte die angefragte Ressource nicht gesendet werden." Angeblich aber bei mir doch. Weiss auch nicht wie ich das testen koennte.

Liest die erste Zeile ein.


```
String requestLine = br.readLine(); // Zeile vom Socket lesen
```

Schaut ob die erste Zeile Head oder Post Kommando enthaelt:


```
if (requestLine.contains("HEAD")) { // true stellen spaeter passende nachricht
         posthead = true;
        }

        if (requestLine.contains("POST")) {
        posthead = true;
        }
```

Wenn eins dieser Kommandos enthaelt, wird also die Variable posthead auf true gestellt.

Hier lasse ich dann die betreffende Fehlermeldung wiedergeben.


```
if (posthead) {
          statusLine = "HTTP/1.0 501 Not Implemented" + CRLF; // so muss es formuliert werden
          contentTypeLine =  "Content-type: " + "text/html" +  CRLF; // weil darunter html code folgt
          entityBody = "<HTML>" +
              "<HEAD><TITLE>Head u Post nicht erlaubt</TITLE></HEAD>" + // fehlermeldung client head u post
              "<BODY>Head u Post nicht erlaubt</BODY></HTML>";
```

Oder liegt es wieder am Objekt Fehler. Also dass ich immer das gleiche Objekt beabreite? Dass ich die Zeile zu weit gelesen habe?
Vorher im Code kam das hier: Wenn ich das GET uebersprungen habe, habe ich dann auch spaeter das HEAD/POST uebersprungen?


```
// Extract the filename from the request line.
      StringTokenizer tokens = new StringTokenizer(requestLine); // zeile aufgespalten
      tokens.nextToken();  //  ueberspringen das Token das GET enhaelt
      String fileName = tokens.nextToken(); // Dateinamen u Ort den Client haben will
```


----------



## mrBrown (23. Nov 2016)

Könntest du vllt etwas zusammenhängenden Code posten und nicht nur einzelne Blöcke?

So könnte der Fehler überall liegen, zB wie du sagst beim Token überspringen.


----------



## Flown (23. Nov 2016)

[JAVA]Tags gibt es nicht mehr. Mittlerweile schreibt man Java code so: [code=java]//JAVA CODE HERE[/code]


----------



## Nummer6800 (23. Nov 2016)

Der ganze Code ist aber ziemlich lang:

Weiss jemand vielleicht wie man schnell post bzw. head testen kann?


```
// zum testen http://localhost:6789/index.html
// umschreiben das alles erklaeren kannst
// komplett auf linux laptop testen!! bedenke wie webseite u webseite nicht da etc.. alles testen

import java.io.* ;
import java.net.* ;
import java.util.* ;
import java.net.InetAddress ;
import java.net.Socket;



public final class WebServer
{


public static void main(String[] args) throws Exception
{


// einlesen(args[0]);

// public static String einlesen(String arg) throws IOException, FileNotFoundException{
// FileReader filereader = new FileReader(arg);
// BufferedReader bufferedreader= new BufferedReader(filereader);

String mimort = args[0];


    // Set the port number.
    int port = 6789; // any port higher than 1024

// hier den ort der datei mime eintagen
    //  String mimort = ".\\mime.types";




// Socket fuer eingehende Anfragen anlegen siehe VL Folie

ServerSocket welcomeSocket = new ServerSocket(port); // ? 

// eine while schleife weil immer neue anfragen von clients annimt



while (true) {
    // dank accept: an diesem Socket auf eingehende Anfragen von Client warten, Siehe VL-FOlie

    Socket connectionSocket = welcomeSocket.accept(); // ? 


// ein client hat also angefragt: los gehts

// referenz zu dem verbindungsobjekt an die klasse geben die sich um die verarbeitung der anfragen kuemmert
HttpRequest request = new HttpRequest(connectionSocket, mimort); // ? 

// jede anfrage kriegt ihren eigenen thread
Thread thread = new Thread(request);

// Start the thread.
thread.start();

}


} // This completes the code in main(). 

}







final class HttpRequest implements Runnable
{

    final static String CRLF = "\r\n";
    Socket socket;
        String mimort; // hier der ort wo mime.typ gespeicehrt ist



// Constructor, werden die uebergebenen objekte zugeordnet den referenzen der klasse, einfacher varis sagen
public HttpRequest(Socket socket, String mimort) throws Exception 
{
        this.socket = socket;
        this.mimort = mimort;
}
   


// die run ist das was ausgefuehrt wird im thread .. in ihr wird processHttpRequest() gestartet
public void run()
{
    try {
        processHttpRequest();
    } catch (Exception e) {
        System.out.println(e);
    }
}


    private void processHttpRequest() throws Exception
    {


        // aus klasse WebServer wurde Socket Verbindung uebergeben. HttpRequest(connectionSocket). In dieser Klasse wurde "this.socket"  mit uebergebenen Socket gefuellt




        // wie in VL-Folie nur aufgespalten

    InputStream is = socket.getInputStream(); // ? "is" zeigt auf: socket.getInputStream()  liefert Eingabestream zum lesen der Socketverbindung


       // hier aber "new InputStreamReader(is)" erzeugt was dann in BufferdReader gesteckt wird. kann man so schneller lesen

    BufferedReader br = new BufferedReader(new InputStreamReader(is)); // ? new InputStreamReader Objekt schaffen das der BufferedReader uebernehmen kann

    DataOutputStream os = new DataOutputStream(socket.getOutputStream()); // ? liefert Ausgabestream zum schreiben, DataOutputstream fuer primitive Datentypen
```

Ab hier geht es eigentlich erst richtig los:


```
// die erste zeile lesen die geschickt vom client bekommen
      String requestLine = br.readLine(); // ? Zeile vom Socket lesen



      // analyze the request and send an appropriate response.
      // use only the file name contained in the request line

      // Extract the filename from the request line.
      StringTokenizer tokens = new StringTokenizer(requestLine); // damit wird die zeile aufgespalten
      tokens.nextToken();  // wir ueberspringen das Token das GET enhaelt 
      String fileName = tokens.nextToken(); // wollen an den Dateinamen u Ort den Client haben will

      // Prepend a "." so that file request is within the current directory.
      fileName = "." + fileName;



      // Now that we have the file name, we can open the file as the first step in sending it to the client. 

      // Open the requested file.
      FileInputStream fis = null;
      boolean fileExists = true;
      try {
          fis = new FileInputStream(fileName);
      } catch (FileNotFoundException e) {
          fileExists = false;
      }



      // Display the request line.
      System.out.println();
      System.out.println(requestLine);


       boolean posthead = false; // erste zeile wenn eins der verbotenen kommandos POST oder HEAD enthaelt

       if (requestLine.contains("HEAD")) { // dann auf true stellen das spaeter passende nachricht schicken
         posthead = true;
        }

        if (requestLine.contains("POST")) {
        posthead = true;
        }



    // Get and display the header lines.
     String headerLine = null;
     String Usagent = null;

     while ((headerLine = br.readLine()).length() != 0) { // alle headerlines ausgeben,.. wie auf folie all die infos wie user agent etc
    System.out.println(headerLine);
        if (headerLine.contains("User-Agent")) {
            Usagent = headerLine; // hier User-Agent speichern z b Modzilla // fuer spaeter 404 nachricht speichern den user agenten
        }
     }




// ganzen teil geht nur darum mime.type liste zu bekommen u diese zu bearbeiten

               String contentType2 = null;

// erstmal hashmap anlegen fuer mime typen, werde spaeter die schluessel z b jpg fuer wert image jpg hier speichern
            Map<String, String> mimespeich = new HashMap<String, String>(); // in hashmap die mime speichern

        try(BufferedReader dateiLeser = new BufferedReader(new FileReader(new File(mimort)));) // fuer dateien nimmt man den Filereader
                        {
           int zeilenNummer = 0;
           String eingabeZeile;

           while((eingabeZeile = dateiLeser.readLine()) != null) { // hier alle zeilen durchgehen
                       
                          if (eingabeZeile.contains("#")){ // nicht benotigte rausschmeissen

                          } else if(!eingabeZeile.isEmpty()) {

                              if (eingabeZeile.contains("    ")){     // "    " alle eintrage hatten sowas als trennwand zu ihren schluesseln

                                eingabeZeile = eingabeZeile.replaceFirst("    ", " ");  // beseitigen der Trennwaene erstes noch durch " "
                                eingabeZeile = eingabeZeile.replace("    ", "");           // spaeter alle


                                 String[] scheibchen =  eingabeZeile.split(" ");   // denn fuer spliten habe ich " " als trennzeichen benutzt

                                 for (int i = 1; i< scheibchen.length; i++){  // split gibt mir ein array
                                     
                                 mimespeich.put(scheibchen[i], scheibchen[0]); // zuerst speichere ich den schluessel z b jpeg dann den mime type image jpeg als Wert in die hasmap
                                               
                                 }
                              } else { } 


                        } else { }  
                         
           }
        } catch (IOException e) {
        }
// ganzen teil ging nur darum mime liste zu bekommen u diese zu bearbeiten



// hier geht es darum die dateiendung herauszubekommen der angefragten datei

String frucht4 = fileName;
String frucht5 = frucht4.replace(".", "/"); // fuers splitten den schraegstrich genommen, da punkte nicht funktioniert, also alle punkte durch straegstich ersetzen

String[] reiben2 = frucht5.split("/");  // also hier per straegstrich splitten
String endung3 = reiben2[reiben2.length-1]; // als das letzte feld des arrays ist dann die dateiendung


        if (mimespeich.containsKey(endung3)) {  // hier fragt ob die uergebene dateiendung einem schluessel gleicht in der hashmap also in mime type liste ist
            //key exists
              contentType2 = mimespeich.get(endung3);  // ist drin, also den mimetyp z b image jpg der vari uebergeben wird spaeter gebraucht
        } else {
            //key does not exists
              contentType2 = "application/octet-stream";
        }



      // There are three parts to the response message: the status line, the response headers, and the entity body. The status line and response headers are terminated by the character sequence CRLF.

      // Construct the response message.
      String statusLine = null;
      String contentTypeLine = null;
      String entityBody = null;


      if (posthead) {
          statusLine = "HTTP/1.0 501 Not Implemented" + CRLF; // ? so muss es formuliert werden
          contentTypeLine =  "Content-type: " + "text/html" +  CRLF; // ? weil darunter html code folgt: rfc1945.txt 10.5 : Content-Type: text/html
          entityBody = "<HTML>" + 
              "<HEAD><TITLE>Head u Post nicht erlaubt</TITLE></HEAD>" + // fehlermeldung falls client head u post methoden versucht hat
              "<BODY>Head u Post nicht erlaubt</BODY></HTML>";

      } else if (fileExists) {
          statusLine = "HTTP/1.0 200 OK" + CRLF; // ? rfc1945.txt: (e.g., "HTTP/1.0 200 "), Reason-Phrase "OK"
          contentTypeLine = "Content-type: " + 
              contentType2 + CRLF; // hier dann den mimpe type in contentType2 drin
      } else {
          statusLine = "HTTP/1.0 404 Not Found" + CRLF; // ? 404 Not Found wie in Aufgabenstellung angegeben
          contentTypeLine =  "Content-type: " + "text/html" +  CRLF; // ? weil darunter html code folgt: rfc1945.txt 10.5 : Content-Type: text/html
          entityBody = "<HTML>" + 
              "<HEAD><TITLE>Not Found</TITLE></HEAD>" +
              "<BODY>Not Found, " + Usagent + " , "  + socket.getLocalAddress() + "</BODY></HTML>"; // socket.getLocalAddress() liefert mir die ip adresse des clienten
      }




      // Now we can send the status line and our single header line to the browser by writing into the socket's output stream. 

      // Send the status line.
      os.writeBytes(statusLine);

      // Aufgabe: Send the content type line.
      os.writeBytes(contentTypeLine); // ? content type line ist die vari contentTypeLine von oben

      // Send a blank line to indicate the end of the header lines.
      os.writeBytes(CRLF);


      // Now that the status line and header line with delimiting CRLF have been placed into the output stream on their way to the browser, it is time to do the same with the entity body.

      // Aufgabe: Send the entity body. .. die angefragte datei existiert also dem clienten liefern
      if (fileExists)    {
          sendBytes(fis, os);
          fis.close();
      } else {
          os.writeBytes(entityBody);  // ? entity body ist entityBody von oben also die error message die html vorbereitet
      }




    // Close streams and socket. mit fehlermeldungen so dass weiss welcher socket aerger macht

try {
    os.close();
    }
    catch (IOException e)
    {
    System.err.println("Konnte nicht schliessen socket1");
    }

try {
    br.close();
    }
    catch (IOException e)
    {
    System.err.println("Konnte nicht schliessen socket2");
    }

try {
    socket.close();
    }
    catch (IOException e)
    {
    System.err.println("Konnte nicht schliessen socket3");
    }

}



// hier mussten wir nichts veraendern .. vermutlich was zum versenden ..

private static void sendBytes(FileInputStream fis, OutputStream os) 
throws Exception
{
   // Construct a 1K buffer to hold bytes on their way to the socket.
   byte[] buffer = new byte[1024];
   int bytes = 0;

   // Copy requested file into the socket's output stream.
   while((bytes = fis.read(buffer)) != -1 ) {
      os.write(buffer, 0, bytes);
   }
}




}
```


----------



## mrBrown (23. Nov 2016)

Wird POST und HEAD in Uppercase gesendet?



Nummer6800 hat gesagt.:


> Weiss jemand vielleicht wie man schnell post bzw. head testen kann?



cURL

Oder Code anders strukturieren und UnitTests nutzen


----------

