Background: I'm getting introduced to clients and servers, and decided to make a simple proxy server.
What the code does as of now: The client side asks for a www.(enter site here).whatever (org, com, edu, etc.) then, the server takes that input in, and calls my WebsiteToHTML class, which converts that whole page to a byte array. The server then stores that byte array to it's own byte array variable. The server then sends the size of that array back to the client, and then sends the byte array itself back to the client. Then, the client makes a byte array of the size sent from the server, and then makes the byte array equal to the byte array that the server sent back. I then have an html string that is made from looping through the byte array and appending all of the chars to the String. I then use WebView to output that String using the loadContent function.
My Problem: My problem lies in outputting images. For instance, if I wanted to go to www.google.com, my code would run perfectly, and the WebView does indeed output the google page. However, the big "Google" logo simply just says "google" in text. My guess is that the WebView doesn't pull the images from the href in the html. Thus, I am here.
My Code:
ProxyClient:
package proxy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.awt.AWTEvent;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.swing.JButton;
import javafx.application.*;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
#SuppressWarnings("restriction")
public class ProxyClient extends Application{
public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
final String IP = "localhost";
byte[] b;
final int PORT = 4444;
String input;
Socket s = new Socket(IP,PORT);
DataOutputStream out = new DataOutputStream(s.getOutputStream());
Scanner scan = new Scanner(System.in);
InputStream inFromServer = s.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
String html = "";
System.out.println("Enter URL: ");
input = scan.next();
out.writeUTF(input);
System.out.println("output sent: " + input);
byte[] htmlBytes = new byte[in.readInt()];
in.read(htmlBytes);
for(int i = 0; i < htmlBytes.length; i++) {
char c = (char)(htmlBytes[i] >= 0 ? htmlBytes[i] : htmlBytes[i]+256);
html += c;
}
System.out.println(html);
primaryStage.setTitle("Proxy Client");
WebView webView = new WebView();
webView.getEngine().loadContent(html);
VBox vBox = new VBox(webView);
Scene scene = new Scene(vBox, 960, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Proxy Server:
package proxy;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
public class ProxyServer {
public static void main(String[] args) throws IOException, InterruptedException {
final int PORT = 4444;
ServerSocket ss = new ServerSocket(PORT);
Socket s = ss.accept();
System.out.println("Connection Established");
DataInputStream in = new DataInputStream(s.getInputStream());
DataOutputStream out = new DataOutputStream(s.getOutputStream());
WebsiteToHTML converter;
String site;
site = "https://"+in.readUTF();
converter = new WebsiteToHTML(site);
byte[] html = converter.write();
System.out.println("Link Receieved received: " + site);
System.out.println("Converted HTMLto byte array: " + Arrays.toString(html));
while(true) {
out.writeInt(html.length);
out.write(html);
}
}
}
WebsiteToHTML:
package proxy;
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.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import javax.net.ssl.HttpsURLConnection;
public class WebsiteToHTML {
URL myurl;
String html;
HttpsURLConnection con;
InputStream ins;
InputStreamReader isr;
BufferedReader in;
String masterString = "";
byte[] b;
public WebsiteToHTML(String httpsURL) throws IOException {
myurl = new URL(httpsURL);
con = (HttpsURLConnection) myurl.openConnection();
ins = con.getInputStream();
isr = new InputStreamReader(ins);
in = new BufferedReader(isr);
}
public byte[] write() throws IOException {
String inputLine;
while ((inputLine = in.readLine()) != null) {
masterString += inputLine + "\n";
}
b = masterString.getBytes();
b = masterString.getBytes(Charset.forName("UTF-8"));
in.close();
return b;
}
}
Related
My server looks like this:
package marshexample;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.net.ServerSocket;
import java.net.Socket;
public class marshServer {
private ServerSocket ses;
private Reader br;
private OutputStream os;
public marshServer() {
StringBuilder sb = new StringBuilder();
try {
ses = new ServerSocket(7824);
Socket s = ses.accept();
br = new InputStreamReader(s.getInputStream());
char[] request = new char[6];
int count = br.read(request);
while (!sb.toString().contains("project")) {
sb.append(new String(request, 0, count));
count = br.read(request);
System.out.println(sb.toString());
}
System.out.println(sb);
os = s.getOutputStream();
os.write("string from server".getBytes());
os.write("empty line".getBytes());
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(sb);
}}
The issue is I have to add the string os.write("empty line".getBytes()); in order to make it work correctly. Without this string the massage is not fully sent to the client. (The same situation is with client). So why flush method does not solve this problem? Thank you for any ideas!
I'm using com.sun.net.HttpServer class to build a http server with java like the following:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class SimpleHttpServer {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8989), 0);
server.createContext("/", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
//Read the request
InputStream in = httpExchange.getRequestBody();
StringWriter writer = new StringWriter();
IOUtils.copy(in, writer);
String inputString = writer.toString();
//prepare the response
httpExchange.sendResponseHeaders(200, "Hi my faithful client".length());
OutputStream os = httpExchange.getResponseBody();
os.write("Hi my faithful client".getBytes());
os.close();
}
}
}
I'm communicating with this server using this client:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
public class Main {
public static void main(String argv[]) throws IOException{
String urlstr = "http://127.0.0.1:8989";
URL url = new URL(urlstr);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write("Hello HTTP server!! I'm your client1");
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String line;
while((line = reader.readLine()) != null) {
result.append(line);
System.out.println(result.toString());
}
}
}
and it'fine working.
but what I want now is that the server allows the client to communicate with him for a session that means a sequence of request/response not just only one. So it will be a loop of request/response. For this purpose I tried to add as a first step just one request to the client by adding to it those two lines:
writer.flush();
writer.write("Hello HTTP server!! I'm your client2");
But it doesn't work. Just the first request is caught by the server.
How can I change the code to achieve my purpose?
Please check the code below:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
public class Test1 {
static String urlstr = "http://127.0.0.1:8989";
public static void main(String argv) throws IOException{
URL url = new URL(urlstr);
Test1 t = new Test1();
for (int i = 0; i < 10; i++) {
t.sendRequest("Hello HTTP server!! I'm your client" + i, url);
}
}
private void sendRequest(String strToSend, URL url) throws IOException{
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(strToSend);
InputStream in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder result = new StringBuilder();
String line;
while((line = reader.readLine()) != null) {
result.append(line);
System.out.println(result.toString());
}
}
}
This is the code on server side, please help me to understand where I am going wrong.
I am uploading an byte array of image as JSON object. Converting the byte array and saving it on disk.
package com.file.up;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.imageio.ImageIO;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.json.JSONObject;
#Path("/")
public class FileUp {
#POST
#Path("/crunchifyService")
#Consumes(MediaType.APPLICATION_JSON)
public Response crunchifyREST(JSONObject incomingData) {
String s="Success!";
try {
String jsonString = incomingData.getString("image");
byte[] a=jsonString.getBytes();
InputStream input=new ByteArrayInputStream(a);
BufferedImage b=ImageIO.read(input);
ImageIO .write(b,"png",new File("C:\\Users\\Uma\\Desktop\\WEB_AND"));
} catch (Exception e) {
System.out.println("Error Parsing: - ");
}
System.out.println("Data Received: ");
// return HTTP response 200 in case of success
return Response.status(200).entity(s).build();
}
}
This is my client side code.
package com.file.up;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.Base64;
import javax.imageio.ImageIO;
import org.json.JSONObject;
public class FileClient {
public static void main(String[] args) throws IOException {
BufferedImage image;
image = ImageIO.read(new File("12.png"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write( image, "png", baos );
baos.flush();
byte[] imageInByte = baos.toByteArray();
String base64String = Base64.getEncoder().encodeToString(imageInByte);
baos.close();
// Step2: Now pass JSON File Data to REST Service
try {
JSONObject jsonObject = new JSONObject("{\"image\":\"" + base64String + "\"}");
System.out.println(jsonObject);
URL url = new URL("http://<ip>:9999/FileUpload/api/crunchifyService");
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
// out.write(jsonObject.toString());
out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
while (in.readLine() != null) {
}
System.out.println("\nREST Service Invoked Successfully..");
in.close();
} catch (Exception e) {
System.out.println("\nError while calling REST Service");
System.out.println(e);
e.printStackTrace();
}
}
}
And the stack trace is
java.io.IOException: Server returned HTTP response code: 500 for URL: http://:9999/FileUpload/api/crunchifyService
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1838)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1439)
at com.file.up.FileClient.main(FileClient.java:64)
I copied your classes in my TomEE server and from the client I am getting no body on the request, you should try using a jaxrs client
I am currently working on a project that will involve communication of applications written in C and Java. Therefore, I chose to work with Apache Avro. I have seen on the website that Avro can (de-)serialize objects from files using the DataFileWriter class.
But, in my case I want to use TCP sockets between my applications. Therefore, DataFileWriter class is not going to work for me. After reading the documentation, I have not found any information on how to send objects through TCP sockets.
Any ideas on how to do that? I specifically want to know what kind of Input and Output Streams I should use on the Java Clients.
I have developed the following code for the Java Server:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.HashMap;
import middleman.bigpeer.BigPeer;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
public class MiddleManWorker implements Runnable {
private InputStream in;
private OutputStream out;
private Socket clientSocket;
public MiddleManWorker(Socket clientSocket, HashMap<Integer, NodeType> dbNodesDirectory,
HashMap<Integer, NodeType> workersDirectory) {
this.clientSocket = clientSocket;
try {
this.in = clientSocket.getInputStream();
this.out = clientSocket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
EncoderFactory encoderFactory = new EncoderFactory();
DecoderFactory decoderFactory = new DecoderFactory();
BinaryEncoder binaryEncoder = encoderFactory.binaryEncoder(out, null);
BinaryDecoder binaryDecoder = decoderFactory.binaryDecoder(in, null);
SpecificDatumReader<BigPeer> peerDatumReader = new SpecificDatumReader<BigPeer>(BigPeer.class);
BigPeer bigPeer = null;
SpecificDatumWriter<BigPeer> writer = new SpecificDatumWriter<BigPeer>();
try {
peerDatumReader.read(bigPeer, binaryDecoder);
System.out.println("Received: " + bigPeer.getType());
} catch (IOException e) {
e.printStackTrace();
}
try {
writer.write(bigPeer, binaryEncoder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
A sample Java Client is the following:
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import middleman.bigpeer.BigPeer;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.specific.SpecificDatumReader;
import org.apache.avro.specific.SpecificDatumWriter;
public class SystemClient {
public static void connect(String serverIPAddress, Integer serverPort) throws IOException, ClassNotFoundException {
/**
* Create Connection with the server
*/
Socket socket = new Socket(serverIPAddress, serverPort);
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
EncoderFactory encoderFactory = new EncoderFactory();
DecoderFactory decoderFactory = new DecoderFactory();
BinaryEncoder binaryEncoder = encoderFactory.binaryEncoder(out, null);
BinaryDecoder binaryDecoder = decoderFactory.binaryDecoder(in, null);
BigPeer bigPeer = new BigPeer();
bigPeer.setType("test");
SpecificDatumReader<BigPeer> reader = new SpecificDatumReader<BigPeer>(BigPeer.class);
SpecificDatumWriter<BigPeer> writer = new SpecificDatumWriter<BigPeer>(BigPeer.class);
System.out.println("Before: " + bigPeer.getType());
writer.write(bigPeer, binaryEncoder);
System.out.println("Waiting for response...");
reader.read(bigPeer, binaryDecoder);
System.out.println("After: " + bigPeer.getType());
}
}
And the server seems to halt on the peerDatumReader.read(bigPeer, binaryDecoder); line of code. Any ideas?
Thank you,
Nick
BinaryEncoder uses an internal buffer for performance reasons. You may need to call flush on the encoder to send the data through the pipe.
See the reference for more information on this behaviour:
The BinaryEncoder implementation returned may buffer its output. Data may not appear on the underlying OutputStream until Flushable.flush() is called. The buffer size is configured with configureBufferSize(int).
If buffering is not desired, and lower performance is acceptable, use directBinaryEncoder(OutputStream, BinaryEncoder)
I am trying to serialize an object in a HttpHandler class.
I have 2 files, Server3.java:
package server3;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class Server3 {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(3333), 0);
server.createContext("/", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String response = "Kjo eshte nje pergjigje nga serveri! n";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
Personat obj = new Personat();
ObjectOutputStream objOut = new ObjectOutputStream(t.getResponseBody());
objOut.writeObject(obj);
objOut.close();
}
}
}
class Personat implements Serializable{
private static final long serialVersionUID = 1L;
int ID=3;
String Name="Andi";
}
and Client3.java:
package server3;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
//te gjithe personat qe jan ne database me nej objekt
public class Client3 {
public static void main(String[] args) throws Exception {
try {
URL url = new URL("http://localhost:3333");
HttpURLConnection s = (HttpURLConnection) url.openConnection();
s.setDoOutput(true);
s.setDoInput(true);
s.setRequestMethod("POST");
s.setUseCaches(false);
InputStream in = s.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
int c;
while ((c = br.read()) != -1) {
System.out.print((char) c);
}
ObjectInputStream ios = new ObjectInputStream(s.getInputStream());
Personat oin = (Personat) ios.readObject();
String emri=oin.Name;
System.out.println(emri);
ios.close();
s.disconnect();
} catch (IOException ex) {
System.err.println(ex);
System.out.print(ex);
}
}
}
But when I run it eclipse shows me
java.io.EOFException Kjo eshte nje pergjigje nga serveri! njava.io.EOFException`
and I cant understand why.
The problem is that you are trying to fit both the string response and the object into response.length() bytes. What happens is that only response.length() bytes are sent and so if you try to read more you get the EOFException.
If you instead set the responseLength parameter to be 0 it will allow you to transmit an arbitrary amount of data
t.sendResponseHeaders(200, 0);
You also shouldn't close the stream if you are going to write more data into it. Don't call os.close() until all the writing is complete.