HTTP No request data found

Yissu

Mitglied
Hallo Leute,

Ich hab ein kleines Problem ich versuch gerade ein kleinen Webserver zu schreiben allerdings bekomme ich immer diese Fehlermeldung:
java.lang.IllegalArgumentException: No request data found

Java:
package com.yissugames.web;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Webserver {

	public Webserver(int port)
	{
		try {
			final ServerSocket socket = new ServerSocket(port);
			
			for(;;) {
				final Socket clientSocket = socket.accept();
				
				final HTTPWorker httpWorker = new HTTPWorker(clientSocket);
				(new Thread(httpWorker)).run();
			}
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(1);
		}
	}
	
	public static void main(String[] args)
	{
		int port = 80;
		if(args.length == 1) 
		{
			if(isInteger(args[0]))
			{
				port = Integer.parseInt(args[0]);
			}
		}
		
		new Webserver(port);
	}
	
	private static boolean isInteger(String s)
	{
		try{
			Integer.parseInt(s);
			return true;
		} catch (Exception e) {
			return false;
		}
	}
	
}

class HTTPWorker implements Runnable
{
	private Socket clientSocket;
	
	public HTTPWorker(final Socket clientSocket)
	{
		this.clientSocket = clientSocket;
	}
	
	@Override
	public void run() {
		System.out.println("====================");
		
		try {
			final InputStream is = clientSocket.getInputStream();
			
			final int bytesToRead = is.available();
			
			if(bytesToRead == 0) {
				throw new IllegalArgumentException("No request data found");
			}
			
			final byte[] barray = new byte[bytesToRead];
			is.read(barray, 0, bytesToRead);
			final String client_data = new String(barray);
			
			final String regex = ".*GET (.*) HTTP.*";
			final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE | Pattern.DOTALL);
			final Matcher matcher = pattern.matcher(client_data);
			
			if(matcher.matches()) {
				final String requestedPage = matcher.group(1);
				
				final String content = "";
				final String data = buildHeader(content.length(), "404 Not Found");
				
				clientSocket.getOutputStream().write(data.getBytes());
				clientSocket.getOutputStream().write(content.getBytes());
				System.out.println("404-Error");
			}
		} catch (final Exception e) {
			e.printStackTrace();
			
			final String content = "<html><head><title>500 - Internal Server Error</title></head><body><h1>500 - Internal Server Error</h1>" + e.getMessage() + "<br /><pre>" + stackTraceToString(e.getStackTrace()) + "</pre></body></html>";
			final String data = buildHeader(content.length(), "500 Internal Server Error");
			
			try {
				clientSocket.getOutputStream().write(data.getBytes());
				clientSocket.getOutputStream().write(content.getBytes());
				System.out.println("Server-Error");
			} catch (final Exception e2) {
				System.out.println("Can't answere to server");
			}
		} 
		
		System.out.println("====================");
	}
	
	private String buildHeader(final int stringLength, final String httpState)
	{
		return "HTTP/1.1 " + httpState + "\n" + "Content-Length: "
				+ stringLength + "\n" + "Content-Type: text/html\n"
				+ "Connection: close\n\n";
	}
	
	private String stackTraceToString(StackTraceElement[] stacktrace)
	{
		StringBuilder builder = new StringBuilder();
		for(StackTraceElement element: stacktrace)
		{
			builder.append(element);
			builder.append(System.getProperty("line.separator"));
		}
		return builder.toString(); 
	}
	
	private void closeSocketNE()
	{
		try 
		{
			clientSocket.close();
		} catch(IOException e) {
			e.printStackTrace();
		}
	}
}
 
gut .. auch wenn der user gesperrt wurde (yeah .. ich kenn das ja irgendwoher ...) vielleicht liest er die antwort trotzdem

InputStream.available() gibt eine grobe schätzung zurück wie viele bytes beim nächsten call von InputStream.read() bzw InputStream.skip() OHNE blockieren gelesen / geskipt werden können ...

da du diese methode direkt nach dem erzeugen des InputStreams aufrufst kann es sein das der input-buffer einfach noch keine daten bzw zu wenig daten enthält um beim nächsten call von read() ohne blockierung weiter zu machen ...

warum du hier überhaupt InputStream.available() callst ist mir ein rätzel ... denn in der regel beginnt man dierekt von einem InputStream zu lesen anstatt gleich nach erzeugen des objektes zu gucken ob man denn schon ohne i/o-block lesen kann ...

schmeiß die zeile also einfach raus und lies stattdessen ein byte-array von sagen wir 8kb ein .. das sollte für ne normale GET-anfrage dicke ausreichen ...

mal ganz davon abgesehen das dein code eh mist ist ...

beispiel : wenn InputStream.available() so arbeiten sollte wie du es hier verwenden willst ... was würdest du machen wenn ich dir im request mal eben 4GB payload schicke ?

1) ein INT kann nur max 2^31-1 darstellen ... was rund 2GB und n bisschen sind ...
2) dein code ist so aufgebaut das du alles gleichzeitig auf einmal in den RAM lesen willst ... solltest du also payload unterstützen wollen müsstest du , da mehrere threads , ein weit aus vielfaches an RAM deiner VM zuweisen ... womit man das ganze system lahmlegen kann (stichwort DDoS)
3) im falle das NICH GET kommt machst du einfach gar nichts ... richtiger weise müsste aber HTTP 501 NOT IMPLEMENTED kommen ...
 
Wie trääät schon richtig angemerkt hat solltest du besser ohne InputStream#available() arbeiten. Lies einfach solange Daten aus dem InputStream bis direkt nacheinander zwei Zeilenumbrüche (also eine Leerzeile) bekommst. Als Zeilenumbruch ist in HTTP übrigens \r\n definiert. Wenn du nur \n sendest wird das sehr warscheinlich in einigen Clients Probleme machen. Ansonsten fällt mir noch ein Fehler bei dem Content-Length Header auf: du sendest die Anzahl der Zeichen im String, es muß dort aber die Anzahl der bytes in der Antwort kommen. (je nach Zeichensatz gibt es da kleinere oder größere Abweichungen)
 

Zurück
Oben