I am trying to write a Java web server from scratch (for learning) and I am bit stuck on how should I end my HTTP response body so that I can get the proper response object at client side.
I am see the 200 OK response, as well 2 other headers I am setting.
HTTP/1.1 200 OK
Connection: close
Content-Type: text/plain
Even I am able to see the response I am writing on the client socket's o/p stream, but problem is that since I think I am missing proper ending of the HTTP response body so I am not able to get correct xmlhttp.status
code and also not able to view the response in Chrome's inspect element, even though HTTP response code is 200 but response preview says "no response data available".
Below is my web server code and client code (XHR based) which I am using to call my web server.
Web server code:
package com.learn;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TestWebServer {
public static void main(String[] args) throws IOException {
startWebServer();
}
/**
* test "backlog" in ServerSocket constructor
test -- If <i>bindAddr</i> is null, it will default accepting
* connections on any/all local addresses.
* @throws IOException
*/
private static void startWebServer() throws IOException {
ServerSocket serverSocket = new ServerSocket(8001);
while(true){
// a "blocking" call which waits until a connection is requested
/*Socket clientSocket = serverSocket.accept();*/
TestWebServer.SocketThread socketThread = new TestWebServer().new SocketThread();
socketThread.setClientSocket(serverSocket.accept());
Thread thread = new Thread(socketThread);
thread.start();
}
}
public class SocketThread implements Runnable{
Socket clientSocket;
public void setClientSocket(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run(){
System.out.println("####### New client session started.");
try {
listenToSocket();
} catch (IOException e) {
System.err.println("#### EXCEPTION.");
e.printStackTrace();
}
}
private void listenToSocket() throws IOException {
/*BufferedReader clientSocketReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter clientSocketWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));*/
InputStreamReader clientSocketReader = (new InputStreamReader(clientSocket.getInputStream()));
OutputStreamWriter clientSocketWriter = (new OutputStreamWriter(clientSocket.getOutputStream()));
int clientSocketInput;
boolean isFirstLineFeedEncountered = false;
boolean isFirstCarriageReturnEncountered = false;
boolean isSecondCarriageReturnEncountered = false;
while(clientSocket.isConnected() && (clientSocketInput = clientSocketReader.read()) != 0){
if(isFirstCarriageReturnEncountered){
//System.out.println("### After first CR");
if(isFirstLineFeedEncountered && isFirstCarriageReturnEncountered){
if(isFirstLineFeedEncountered && isFirstCarriageReturnEncountered && isSecondCarriageReturnEncountered){
System.out.println("### 2 sets of CRLF encountered.");
String responseHeaders = construct_http_header(200);
clientSocketWriter.append(responseHeaders);
clientSocketWriter.append("Bye from server, thank you for contacting me!!!");
clientSocketWriter.append("\r\n\r\n");
clientSocketWriter.flush();
clientSocketWriter.close();
clientSocketReader.close();
clientSocket.close();
break;
} else if(clientSocketInput == 13){
//System.out.println("### After first set of CRLF, found another CR");
isSecondCarriageReturnEncountered = true;
} else{
//System.out.println("### Oops, after first set of CRLF");
isFirstLineFeedEncountered = false;
isFirstCarriageReturnEncountered = false;
isSecondCarriageReturnEncountered = false;
}
} else if(clientSocketInput == 10){
//System.out.println("### First LF");
isFirstLineFeedEncountered = true;
} else{
isFirstCarriageReturnEncountered = false;
}
}
// identify "CR" or ASCII 13
if(clientSocketInput == 13){
//System.out.println("### First CR");
isFirstCarriageReturnEncountered = true;
}
// identify "CTRL+C" or ASCII 3
if(clientSocketInput == 3){
System.out.println("### Encountered CTRL+C");
clientSocketWriter.append("Bye from server, thank you for contacting me!!!");
clientSocketWriter.flush();
clientSocketWriter.close();
clientSocketReader.close();
clientSocket.close();
break;
}
// identify "CTRL+D" or ASCII 4
if(clientSocketInput == 4){
System.out.println("### Encountered CTRL+D");
clientSocketWriter.append("Bye from server, thank you for contacting me!!!");
clientSocketWriter.flush();
clientSocketWriter.close();
clientSocketReader.close();
clientSocket.close();
break;
}
System.out.print((char) clientSocketInput);
}
}
/**
* SOURCE: https://fragments.turtlemeat.com/javawebserver.php
*
* @param return_code
* @param file_type
* @return
*/
private String construct_http_header(int return_code) {
String s = "HTTP/1.1 ";
// you probably have seen these if you have been surfing the web a
// while
switch (return_code) {
case 200:
s = s + "200 OK";
break;
case 400:
s = s + "400 Bad Request";
break;
case 403:
s = s + "403 Forbidden";
break;
case 404:
s = s + "404 Not Found";
break;
case 500:
s = s + "500 Internal Server Error";
break;
case 501:
s = s + "501 Not Implemented";
break;
}
s = s + "\r\n"; // other header fields,
s = s + "Connection: close\r\n"; // we can't handle persistent connections
/*s = s + "Server: SimpleHTTPtutorial v0\r\n"; // server name*/
s = s + "Content-Type: text/plain\r\n";
// //so on and so on......
s = s + "\r\n"; // this marks the end of the httpheader
// and the start of the body
// ok return our newly created header!
return s;
}
}
}
Client code:
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
</head>
<body>
<div>
<label class="title">First Name</label>
<input type="text" id="name" name="name" >
</div>
<div>
<label class="title">Name</label>
<input type="text" id="name2" name="name2" >
</div>
<div>
<input type="submit" id="submitButton" name="submitButton" value="Submit">
</div>
<script type='text/javascript'>
/* attach a submit handler to the form */
$("#submitButton").click(function(event) {
//var message=obj["message"].value;
var data = "message=";
var xmlhttp;
try{
// Opera 8.0+, Firefox, Safari
xmlhttp = new XMLHttpRequest();
}catch (e){
// Internet Explorer Browsers
try{
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}catch (e) {
try{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}catch (e){
// Something went wrong
alert("Your browser broke!");
return false;
}
}
}
url = "http://localhost:8001/"
xmlhttp.open("POST", url , true);
xmlhttp.onreadystatechange = display_data;
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlhttp.send(data);
function display_data() {
if(xmlhttp.readyState == 1 ) {
alert("OPENED");//check if the data was revived successfully.
}
if(xmlhttp.readyState == 2 ) {
alert("Headers Received");//check if the data was revived successfully.
}
if(xmlhttp.readyState == 3 ) {
alert("Loading response entity body");//check if the data was revived successfully.
}
if(xmlhttp.readyState == 4) {
alert("a"+xmlhttp.status);
console.log("############");
console.log(xmlhttp);
if (xmlhttp.status == 200) {
alert("Data transfer completed");//check if the data was revived successfully.
}
}
}
});
</script>
</body>
</html>
P.S. Please do not recommend me to use some Java web server API, this is for my learning on how to implement a web server so I am looking for insight on my issue.
Update: I think I got something, may be I need to also include the content length header so I included the same
s = s + "Content-Length: 51\r\n";
and now I am able to see content length header as well but still problem remains same that neither in XHR nor in Chrome inspect element I am able to see the server response.