Web server hanging. I have no idea why - java

I'm writing a very tiny, very sh*tty web server just for fun. It was working fine with GET requests or returning a 404. And worked very briefly working with POST requests. And now it just hangs on any POST request.
Here is the relevant bit of code. As you can see I put in some logging to both System.out and to a file. The logging to System.out works, but the logging to file never happens. If I remove the logging to file, it still hangs on the line after System.out log. I included the few lines previous so you can see that it is the exact same code as returning a 404. 404 works, but POST doesn't. This is using a ServerSocket. I'm at a complete loss at this point. Would appreciate any insight.
Edit: Have included the main and sendResponse methods in case there is anything in there that might be causing this.
Edit #2: Ima just post the whole thing.
package beerio;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class Beerio {
public static void main( String[] args ) throws Exception {
try (ServerSocket serverSocket = new ServerSocket(80)) {
while (true) {
try (Socket client = serverSocket.accept()) {
handleClient(client);
}
catch(Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
BufferedWriter writer = new BufferedWriter(new FileWriter("errorlog.txt", true));
writer.append(System.lineSeparator());
writer.append(sw.toString());
writer.append(System.lineSeparator());
writer.close();
continue;
}
}
}
}
private static void handleClient(Socket client) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
//make request into string. this only parses until the first blank line
StringBuilder requestBuilder = new StringBuilder();
String line;
while (!(line = br.readLine()).isBlank()) {
requestBuilder.append(line + "\r\n");
}
//split string and parse into request info
String request = requestBuilder.toString();
String[] requestsLines = request.split("\r\n");
String[] requestLine = requestsLines[0].split(" ");
String method = requestLine[0];
String path = requestLine[1];
String version = requestLine[2];
String host = requestsLines[1].split(" ")[1];
List<String> headers = new ArrayList<>();
for (int h = 2; h < requestsLines.length; h++) {
String header = requestsLines[h];
headers.add(header);
}
//rest of request contains post info. parse that here
if(method.equals("POST")) {
String parameters;
parameters = br.readLine();
String[] temp = parameters.split("&");
String[][] params = new String[temp.length][2];
for(int i=0; i<temp.length; i++) {
params[i][0] = temp[i].substring(0,temp[i].indexOf("="));
params[i][1] = temp[i].substring(temp[i].indexOf("=")+1);
}
}
Path filePath = getFilePath(path);
if (method.equals("GET")) {
System.out.println("doGet");
if (Files.exists(filePath)) {
// file exist
String contentType = guessContentType(filePath);
sendResponse(client, "200 OK", contentType, Files.readAllBytes(filePath));
} else {
// 404
byte[] notFoundContent = "<h1>Not found :(</h1>".getBytes();
sendResponse(client, "404 Not Found", "text/html", notFoundContent);
}
} else if(method.equals("POST")){
byte[] postContent = "<h1>POST Failed Successfully</h1>".getBytes();
sendResponse(client, "200 OK", "text/html", postContent);
}
}
private static void sendResponse(Socket client, String status, String contentType, byte[] content) throws IOException {
OutputStream clientOutput = client.getOutputStream();
clientOutput.write(("HTTP/1.1 " + status+"/r/n").getBytes());
clientOutput.write(("ContentType: " + contentType + "\r\n").getBytes());
clientOutput.write("\r\n".getBytes());
clientOutput.write(content);
clientOutput.write("\r\n\r\n".getBytes());
clientOutput.flush();
client.close();
}
private static Path getFilePath(String path) {
if ("/".equals(path)) {
path = "\\index.html";
}
return Paths.get("C:\\Users\\shawn\\beerio\\beerio\\tmp\\www", path);
}
private static String guessContentType(Path filePath) throws IOException {
return Files.probeContentType(filePath);
}
}

Related

JAVA - not able to update data in file that is "resources" folder

I am a little perplexed by the behavior I see in my proof-of-concept test program.
My Java application uses a file that is placed in "resource" folder in the Java project. The application will occasionally read numeric data from it, use it, increment the number and write it back to the same file for the next cycle.
The following test application mimics the above (wanted) behavior:
public class ReadWriteFile {
private static final String TEMP_EMAIL_ID_DATAFILE_PATH = "main/resources/TempEmailId.dat";
public static void main(String[] args) throws ParseException {
try {
int id = readTempId();
System.out.println("Current value = " + id);
writeTempId(id+5);
System.out.println("Updated value = " + readTempId());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static int readTempId() throws IOException {
InputStream is = ReadWriteFile.class.getClassLoader().getResourceAsStream(TEMP_EMAIL_ID_DATAFILE_PATH);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
int currentValue = 0;
while ((line = br.readLine()) != null) {
currentValue = Integer.parseInt(line);
}
br.close();
return currentValue;
}
public static void writeTempId(int currentId) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("src" + File.separator + TEMP_EMAIL_ID_DATAFILE_PATH));
bw.write(Integer.toString(Math.abs(currentId)));
bw.flush();
bw.close();
return;
}
}
When I run the test, the following is seen:
Current value = 100000054
Updated value = 100000054
My gut feeling is that the use of
ReadWriteFile.class.getClassLoader().getResourceAsStream(TEMP_EMAIL_ID_DATAFILE_PATH);
is causing the issue. I am using this to access the file within the JAVA project.
Can it be true?
Also, note that for creating the BufferedWriter object, I have to pre-pend the Java constant with "src/" - else the file could not be found :(
Thanks.
Resources are intended to be read-only. The only way they could become writable is if they were extracted into the file system, but that's not how they are intended to be used and is not portable as resources are normally in a jar. Write to a file instead
This should work:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException;
public class ReadWriteFile {
private static final String TEMP_EMAIL_ID_DATAFILE_PATH = "TempEmailId.dat";
public static void main(String[] args) throws ParseException, URISyntaxException {
try {
int id = readTempId();
System.out.println("Current value = " + id);
writeTempId(id+5);
System.out.println("Updated value = " + readTempId());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static int readTempId() throws IOException {
InputStream is = ReadWriteFile.class.getClassLoader().getResourceAsStream(TEMP_EMAIL_ID_DATAFILE_PATH);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
int currentValue = 0;
while ((line = br.readLine()) != null) {
currentValue = Integer.parseInt(line);
}
br.close();
return currentValue;
}
public static void writeTempId(int currentId) throws IOException, URISyntaxException {
URL resource = ReadWriteFile.class.getClassLoader().getResource(TEMP_EMAIL_ID_DATAFILE_PATH);
File file = new File(resource.toURI());
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
bw.write(Integer.toString(Math.abs(currentId)));
bw.flush();
bw.close();
return;
}
}
The 2 key lines for writing to file was doing it as such:
URL resource = ReadWriteFile.class.getClassLoader().getResource(TEMP_EMAIL_ID_DATAFILE_PATH);
File file = new File(resource.toURI());

navigate directory structure and name each processed file uniquely

I have a directory structure of the form start/one/two/three/*files*
My goal is to construct this program such that it can navigate my directory structure autonomously, grab each file then process it, which it seems to be doing correctly.
BUT I also need the output to be written to a new file with a unique name, i.e. the file named 00001.txt should be processed and the results should be written to 00001_output.txt
I thought I implemented that correctly but, apparently not.
Where have I gone astray?
String dirStart = "/home/data/";
Path root = Paths.get(dirStart);
Files.walkFileTree(root.toAbsolutePath().normalize(), new SimpleFileVisitor<Path>()
{
#Override
public FileVisitResult visitFile(Path file, java.nio.file.attribute.BasicFileAttributes attrs) throws IOException
{
try(InputStream inputStream = Files.newInputStream(file);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)))
{
// CHANGE OUTPUT TO NEW FILE
String print_file = file.getFileName().toString();
String fileNameWithOutExt = FilenameUtils.removeExtension(print_file);
System.out.println(fileNameWithOutExt);
PrintStream out = new PrintStream(new FileOutputStream( fileNameWithOutExt + "_output.txt" ) );
System.setOut(out);
// SOUP PART
StringBuilder sb = new StringBuilder();
String line = bufferedReader.readLine();
while (line != null)
{
sb.append(line);
sb.append(System.lineSeparator());
line = bufferedReader.readLine();
}
String everything = sb.toString();
Document doc = Jsoup.parse(everything);
String link = doc.select("block.full_text").text();
System.out.println(link);
}
catch (IOException e)
{
e.printStackTrace();
}
return FileVisitResult.CONTINUE;
}
});
This is also my question, it might give some additional insight on what I'm actually trying to do.
System.setOut seems like a bad idea.
Below is some untested code which might work.
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import org.apache.commons.io.FilenameUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
public class App {
public static void main(String[] args) throws IOException {
String dirStart = "/home/data/";
Path root = Paths.get(dirStart);
Files.walkFileTree(root.toAbsolutePath().normalize(), new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file, java.nio.file.attribute.BasicFileAttributes attrs) throws IOException {
// CHANGE OUTPUT TO NEW FILE
String print_file = file.getFileName().toString();
String fileNameWithOutExt = FilenameUtils.removeExtension(print_file);
System.out.println(fileNameWithOutExt);
// SOUP PART
String everything = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
Document doc = Jsoup.parse(everything);
String link = doc.select("block.full_text").text();
try (PrintStream out = new PrintStream(new FileOutputStream(fileNameWithOutExt + "_output.txt"))) {
out.println(link);
} catch (IOException e) {
e.printStackTrace();
}
return FileVisitResult.CONTINUE;
}
});
}
}

StringIndexOutOfBoundsException in Java?

I try to run this java program which returns a webpage in my webroot folder
import java.io.DataOutputStream;
import java.io.File;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class WebServer {
static ServerSocket requestListener;
static Socket requestHandler;
static Scanner requestReader, pageReader;
static DataOutputStream pageWriter;
static String HTTPMessage;
static String requestedFile;
public static int HTTP_PORT = 12346;
public static void main(String[] args) {
try {
requestListener = new ServerSocket(HTTP_PORT);
System.out.println("Waiting For IE to request a page:");
requestHandler = requestListener.accept();
System.out.println("Page Requested: Request Header:");
requestReader = new Scanner(new InputStreamReader(
requestHandler.getInputStream()));
//THis is the part where its throwing the error
int lineCount = 0;
do {
lineCount++; // This will be used later
HTTPMessage = requestReader.next();
System.out.println(HTTPMessage);
if (lineCount == 1) {
requestedFile = "WebRoot\\"
+ HTTPMessage.substring(5,
HTTPMessage.indexOf("HTTP/1.1") - 1);
requestedFile = requestedFile.trim();
}
// localhost:12346/default.htm
// HTTPMessage = requestReader.nextLine();
pageReader = new Scanner(new File(requestedFile));
pageWriter = new DataOutputStream(
requestHandler.getOutputStream());
while (pageReader.hasNext()) {
String s = pageReader.nextLine();
// System.out.println(s);
pageWriter.writeBytes(s);
}
// Tells the Browser we’re done sending
pageReader.close();
pageWriter.close();
requestHandler.close();
} while (HTTPMessage.length() != 0);
} catch (Exception e) {
System.out.println(e.toString());
System.out.println("\n");
e.printStackTrace();
}
}
}
and I get this error message. I am supposed to get a webpage in IE but all I get this error message.
Waiting For IE to request a page:
Page Requested: Request Header:
GET
java.lang.StringIndexOutOfBoundsException: String index out of range: -7
at java.lang.String.substring(Unknown Source)
at WebServer.main(WebServer.java:39)
This error is being thrown because the String 'HTTPMessage' does not contain the string 'HTTP/1.1'. Hence
HTTPMessage.indexOf("HTTP/1.1") => returns -1
So inside yoour substring function this is whats getting passed :
HTTPMessage.substring(5, -2);
Hence the error.
To solve this error, you should first try to check if HTTPMessage contains the required string and then try to compute the substring. Make the following change :
if (lineCount == 1 && HTTPMessage.indexOf("HTTP/1.1") != -1) {
requestedFile = "WebRoot\\"
+ HTTPMessage.substring(5,
HTTPMessage.indexOf("HTTP/1.1") - 1);
requestedFile = requestedFile.trim();
}

Jquery Ajax call served by Java Socket doesn't get a success response

//--------- Java Socket Server --------
package com.company.server;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.net.Socket;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Worker implements Runnable {
private static Logger logger = LoggerFactory.getLogger(Worker.class);
private Socket socket;
public Worker(final Socket socketParam) {
socket = socketParam;
}
public void run() {
logger.trace(String.format("Connection established with %s.", socket.getRemoteSocketAddress()));
orchestrate();
}
public void orchestrate() {
try {
final HttpPacket httpIn = readRequest();
respond(httpIn);
} catch (IOException e) {
e.printStackTrace();
}
}
public HttpPacket readRequest() throws IOException {
final HttpPacket httpIn = new HttpPacket();
final BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
byte[] streamBuf = new byte[in.available()];
in.read(streamBuf);
final String payload = new String(streamBuf, "UTF-8");
final String[] payloadSplit = payload.split(System.getProperty("line.separator"));
final StringBuilder headerBuilder = new StringBuilder();
final StringBuilder bodyBuilder = new StringBuilder();
boolean bodyField = false;
for (int i = 0; i< payloadSplit.length; i++) {
if (i == 0) {
String[] firstLine = payloadSplit[0].split("\\s");
httpIn.setMethod(firstLine[0]);
httpIn.setUrl(firstLine[1]);
} else if ("".equals(payloadSplit[i].trim())) {
bodyField = true;
} else if (bodyField) {
bodyBuilder.append(payloadSplit[i]);
bodyBuilder.append("\n");
} else {
headerBuilder.append(payloadSplit[i]);
headerBuilder.append("\n");
}
}
final Properties props = parsePropertiesString(headerBuilder.toString());
httpIn.setHttpHeaders(props);
httpIn.setBody(bodyBuilder.toString());
logger.trace(String.format("Data received from from %s connection:\n%s",
socket.getRemoteSocketAddress(), payload));
return httpIn;
}
public Properties parsePropertiesString(String s) throws IOException {
final Properties p = new Properties();
p.load(new StringReader(s));
return p;
}
public void respond(final HttpPacket httpIn) throws IOException {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
StringBuilder builder = new StringBuilder();
builder.append("HTTP/1.1 200 OK" + System.getProperty("line.separator"));
builder.append("Content-Type: text/plain" + System.getProperty("line.separator"));
builder.append("Content-Length: " + httpIn.getBody().length()
+ System.getProperty("line.separator") + System.getProperty("line.separator"));
builder.append(httpIn.getBody());
builder.append(httpIn.getBody());
out.write(builder.toString());
out.close();
socket.close();
}
}
//-------------- JQuery Ajax --------------
$(document).ready(function() {
$(".test").click(function() {
testMessage();
});
});
function testMessage() {
var url = "http://localhost/";
$.ajax({
type : 'POST',
url : url ,
contentType: "text/html",
success : function(response, textStatus, jqXHR) {
alert(response);
},
error : function(jqXHR, textStatus, errorThrown) {
alert("Error getting response.");
}
});
};
Intention - When I click on a button (with class="test" in a html page with this js), it should perform an ajax call and get the response back.
Problem - I do not get response body with this ajax call. When I used firebug with mizilla firefox, all I see is "POST http://localhost.uri/ 200 OK -20ms" (forget about the .uri - satisfying this editor) in red with empty body and the error message (ajax error function() is called) in chrome (did not use firebug).
HttpPacket is a data structure internal to the app just to store incoming data.

How do I send Http trailers/footers in a chunked response from within a java servlet?

Basically my response headers contain
Transfer-encoding=chunked,
Trailer=[some trailer I want to send say e.g "SomeTrailer"]
Once I'm done writing the data to the Servlet outputstream, I'm writing the trailer
"SomeTrailer:[value]", but this is not being parsed by the httpclient correctly.
The httpclient considers the whole of inputstream (including the trailer) as a single
chunk.
I've also tried writing the trailer in a response header after the data has been written to the outputstream but without success.
Please help
I haven't found any good sources on this.
I ended up writing a simple single threaded webserver for this. Turned out it was quite easy. The server is pretty simple. The code's a bit rough though, but the main idea is there.
What it does it sends the filecontents as the first chunk and the checksum of the file as a footer.
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
public class ChunkedResponseServer implements Runnable {
private static final Logger LOGGER = Logger.getLogger(ChunkedResponseServer.class);
// Space ' '
static final byte SP = 32;
// Tab ' '
static final byte HT = 9;
// Carriage return
static final byte CR = 13;
// Line feed character
static final byte LF = 10;
final int port;
private volatile boolean cancelled = false;
public ChunkedResponseServer(int port) {
LOGGER.info("Chunked response server running on port " + port);
this.port = port;
}
#Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
while (!cancelled) {
final Socket connectionSocket = serverSocket.accept();
handle(connectionSocket);
}
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
public void cancel() {
LOGGER.info("Shutting down Chunked response Server");
cancelled = true;
}
private void handle(Socket socket) throws IOException {
BufferedReader input = null;
DataOutputStream output = null;
try {
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output = new DataOutputStream(socket.getOutputStream());
addHeaders(output);
addCRLR(output);
final String filename = readFilename(input);
final byte[] content = readContent(filename);
addContentAsChunk(output, content);
final String checksum = DigestUtils.md5Hex(content);
addLastChunkAndChecksumFooter(output, checksum);
addCRLR(output);
} finally {
IOUtils.closeQuietly(input);
IOUtils.closeQuietly(output);
}
}
private void addLastChunkAndChecksumFooter(DataOutputStream output, String checksum) throws IOException {
output.writeBytes("0");
addCRLR(output);
output.writeBytes("checksum: " + checksum);
addCRLR(output);
}
private void addContentAsChunk(DataOutputStream output, byte[] content) throws IOException {
output.writeBytes(Integer.toHexString(content.length));
addCRLR(output);
output.write(content);
addCRLR(output);
}
private void addCRLR(DataOutputStream output) throws IOException {
output.writeByte(CR);
output.writeByte(LF);
}
private void addHeaders(DataOutputStream output) throws IOException {
output.writeBytes("HTTP/1.1 200 OK");
addCRLR(output);
output.writeBytes("Content-type: text/plain");
addCRLR(output);
output.writeBytes("Transfer-encoding: chunked");
addCRLR(output);
output.writeBytes("Trailer: checksum");
addCRLR(output);
}
private String readFilename(BufferedReader input) throws IOException {
final String initialLine = input.readLine();
final String filePath = initialLine.split(" ")[1];
final String[] components = filePath.split("/");
return components[components.length - 1];
}
private byte[] readContent(String filename) throws IOException {
final InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename);
return IOUtils.toByteArray(in);
}
}

Categories