Code
public HttpRequest(BufferedReader from) {
String firstLine = "";
try {
firstLine = from.readLine();
} catch (IOException e) {
System.out.println("Error reading request line: " + e);
}
String[] tmp = firstLine.split(" ");
method = tmp[0];
URI = tmp[1];
version = tmp[2];
System.out.println("URI is: " + URI);
if(method.equals("POST")){
try {
String line = from.readLine();
while (line.length() != 0) {
headers += line + CRLF;
if (line.startsWith("Host:")) {
tmp = line.split(" ");
if (tmp[1].indexOf(':') > 0) {
String[] tmp2 = tmp[1].split(":");
host = tmp2[0];
port = Integer.parseInt(tmp2[1]);
} else {
host = tmp[1];
port = HTTP_PORT;
}
}
line = from.readLine();
}
headers += "Connection: close" + CRLF;
headers += CRLF;
}
catch (IOException e) {
System.out.println("Error reading from socket: " + e);
return;
}
}
else {
System.out.println("Error: Method not supported");
return;
}
System.out.println("Host to contact is: " + host + " at port " + port);
}
Problem
I am making a proxy server using Java.
The code above handles an HTTP POST Request. It successfully reads the POST header and prints it in the command prompt but the body is missing.
Can you take look at my code and see the problem? Thanks.
(NOTE: I excluded the GET part because there were no problems with that.)
Result
The problem is that you still have things to read on the InputStream. That's why when you shut down the browser, there's nothing else to read so is printed. You have to read exactly the number of bytes that is declared in "Content-Length"
Try something like this:
int cL = Integer.valueOf(contentLength);
byte[] buffer = new byte[cL];
String postData = "";
System.out.println("Reading "+ cL + "bytes");
in.read(buffer, 0, cL);
postData = new String(buffer, 0, buffer.length);
System.out.println(postData);
The body request will be in the postData string.
This is not how to write a proxy server. A proxy server only has to do the following:
Accept incoming connections. For each connection:
Read an HTTP CONNECT request.
Connect to the target host specified in the CONNECT request and send an appropriate response to the client.
If the connect succeeded, copy bytes between the upstream server and the downstream client, in both directions simultaneously.
When you read EOS in one direction, shutdown the opposite socket for output.
When you have shutdown in both directions, close both sockets.
That's it. There is no parsing of POST requests or anything else required. Not even a Reader.
Related
I want to get an image from a server by making http request manually . I make a connection , create a http request wait for , get the http reply from server and then i want data inside it.I separated header from data and saved it into a file with ".jpeg" extension . But my .jpeg file could not be opened. What can i do ?
Note: i cant use any plugin or libraries . I just can process on http request!
Here my code :
try (Socket socket = new Socket("ceit.aut.ac.ir", 80)) {
// send an HTTP request to the web server
DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
outToServer.writeBytes("GET /~94131090/CN1_Project_Files/flower.jpeg HTTP/1.1\r\n");
outToServer.writeBytes("Host: ceit.aut.ac.ir:80\r\n");
outToServer.writeBytes("Connection: Close\r\n");
outToServer.writeBytes("Content-Type:image/*\r\n");
outToServer.writeBytes("\r\n");
// Receive an HTTP reply from the web server
boolean loop = true;
StringBuilder sb = new StringBuilder();
while (loop) {
if (inFromServer.ready()) {
int i = 0;
while (i != -1) {
i = inFromServer.read();
sb.append((char) i);
}
loop = false;
}
}
//Download Image
String data = separate(sb.toString());
//???
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
Here my separate function :
public String separate(String str){
String msg = str;
int index = msg.indexOf("close");
// "close" and blank end of http response line including \r\n
// 3(close) + 2(\r) + 2 (\n) + 2 (\r) + 2 (\n) = 4 + 2 + 2 + 2 = 6
return msg.substring(index+11);
}
I am writing a web proxy and so far I can read a GET request from a client, format it, and send it to the server, I believe that I have been able to get the response back from the server, but am unsure of how to send the response to the client.
Scanner readClient = new Scanner(new InputStreamReader(client.getInputStream()));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
System.out.println("Client Request: ");
String request;
String host = "";
String path = "";
String[] parts = new String[4];
while((request = bufferedReader.readLine())!= null) {
if (request.indexOf("deflate") != -1) {
break;
}
if(request.indexOf("GET") != -1){
parts = request.split(" ");
path = parts[1];
System.out.println("THIS IS THE PATH: " + path);
}
if(request.indexOf("Host") != -1){
parts = request.split(": ");
host = parts[1];
System.out.println("THIS IS THE HOST: " + host);
}
System.out.println(request);
}
Socket server = new Socket(host, 80);
System.out.println("Successfully connected to host: " + host);
PrintWriter writeServer = new PrintWriter(new DataOutputStream(server.getOutputStream()));
InputStream readServer = server.getInputStream();
writeServer.print("GET " + path + "\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n");
writeServer.flush();
OutputStream writeClient = client.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buffer[] = new byte[1024];
for(int s; (s=readServer.read(buffer)) != -1; )
{
baos.write(buffer, 0, s);
}
byte result[] = baos.toByteArray();
System.out.println("message sent");
}
catch (Exception e) {
System.out.println("Start Exception: " + e.getMessage());
}
}
** Not sure how I am supposed to record edits made to the question, but I have changed my wording and updated my code as well as included more of it.
You just need to read and copy the input to the output, taking note of the content-length or transfer-encoding headers on the way past, and stop when you exhaust either the content-length or whatever the transfer encoding thinks is the end of the response.
What kind of errors are you trying to catch? Did some homework last term using Scanner(URL.openStream()) and for anything "not normal" that would display as an error in a browser it would throw an Exception. Here's my catch() statement with some comments, it worked for what I needed at the time.
// do we have an error?
catch (Exception ex) {
// rather than specific exceptions related to the type of
// error (network, protocol, webserver content/configuration)
// the java.net.URL.openStream(URL) seems to return
// a different message in .getMessage() that you have to
// parse to figure out what happened.
// would these messages be different in a different java/jvm implementation?
String errorMsg=ex.getMessage();
// nicer errors below
//System.out.println("Error: "+errorMsg+"\n\r");
// what makes up our URL? this lets us get the hostname
// easily as urlParts[2].
String[] urlParts=theURL.split("/");
// on DNS failure (use http://aintthere.example.com as test URL)
// Exception.getMessage() seems to return the desired hostname
if(errorMsg.indexOf(urlParts[2])==0){
System.out.println("DNS error - invalid or unknown hostname");
}
// on a 404 error (use http://www.example.com/aintthere) the
// Exception.getMessage() appears to return the URL requested.
if(errorMsg.indexOf(theURL)==0){
System.out.println("The requested URL does not exist: "+theURL);
}
// no route to host or host off line and/or denying connections
if(errorMsg.indexOf("Connection timed out")==0){
System.out.println("That host is unreachable or is not allowing connections");
}
// turns out lots of different SSL errors - invalid certs, self signed certs, mis-matched hostnames,
// all sorts of things. seems easier to parse for ".security." in the message since
// they seem to come either from java.security.cert.* or sun.security.*
if(errorMsg.indexOf(".security.")!=-1){
System.out.println("Insecure SSL connection attempt - not allowed");
}
// both 500 (Internal Server Error) and 403 (Access to Resource Forbidden)
// produce nice standard looking error messages with the error number in them, so
// we check for that. Why doesn't 404 do that?
if(errorMsg.indexOf("HTTP response code: 500")!=-1){
System.out.println("The webserver is suffering from its own issues - Internal Server Error detected");
}
if(errorMsg.indexOf("HTTP response code: 403")!=-1){
System.out.println("Access to that resource is forbidden by the webserver configuration");
}
} // end catch
I try to push notification from java server to IOS client
and i have this error(response from codename one server)
{"error":"Failed to send push to APNS: com.notnoop.exceptions.NetworkIOException: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake"}
String GOOGLE_SERVER_KEY = "********************************************";
HttpsURLConnection connection;
String url = "https://push.codenameone.com/push/push";
String TOKEN = "******-****-*****-*****-**************";
String URL_ENCODED_LINK_TO_YOUR_P12_FILE =
"https://dl.dropboxusercontent.com/*/******************/Certificates.p12";
String URL_ENCODED_CERTIFICATE_PASSWORD = "******";
String deviceId =
"cn1-gcm-*******************************************************";
String deviceId2 =
"cn1-ios-***************************************************";
String MESSAGE_BODY = "This notification message coming from server";
try {
connection = (HttpsURLConnection)new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
String query =
"token=" + TOKEN + "&device=" + deviceId + "&device=" +
deviceId2 + "&type=1&auth=" + GOOGLE_SERVER_KEY +
"&certPassword=" + URL_ENCODED_CERTIFICATE_PASSWORD +
"&cert=" + URL_ENCODED_LINK_TO_YOUR_P12_FILE + "&body=" +
URLEncoder.encode(MESSAGE_BODY, "UTF-8") + "&production=false";
try {
OutputStream output = connection.getOutputStream();
output.write(query.getBytes("UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("ResponseCode : " + connection.getResponseCode());
System.out.println("ResponsenMessage : " +
connection.getResponseMessage());
BufferedReader br =new BufferedReader(new InputStreamReader((connection.getInputStream())));
String output;
String result = "";
System.out.println("Output .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
result += output + "\n";
}
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
Output from codename one Server
Response Code : 200
Response Message : OK
Output ....
{"error":"Failed to send push to APNS: com.notnoop.exceptions.NetworkIOException: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake"}
A handshake exception would generally mean the Codename One servers failed to connect due to a security issue. This probably means your P12 is incorrect.
Are you sure you used the right P12 file? Keep in mind that there are 2 push certificates (not to be confused with the 2 signing certificates) and only one of them should be used based on the value of the sandbox flag.
Did you use the certificate wizard?
I think 2195 and 2196 ports are disabled on either the server or client side which needs to be enabled for apple push notification.
We would like to create a simple JAVA proxy server that would gather info from the request headers if need be.
We have implemented the proxy server, pointed our browser to the host and port, and we are able to browse sites that use simple HTTP protocol without an issue.
We support the GET and HEAD HTTP methods.
However, sites that use HTTPS cause an issue, as these initiate a CONNECT method, and we can't get the secure connection up, we are not sure what to send in the response. (Or if we would be able to monitor further requests from that point onward.)
Any suggestions? Any 3rd party implementation would do. But we would like to support HTTP and HTTPS in the same process.
private void intercept() throws IOException {
final DataInputStream socketInput = new DataInputStream(this.socket.getInputStream());
final String httpMessage = RequestHeader.readHttpHeader(socketInput);
//Request header is our own convenience file with utility methods that parses the request header.
requestHeader = new RequestHeader(httpMessage);
try {
if ("GET".equals(requestHeader.getType()) || "HEAD".equals(requestHeader.getType())) {
final URL url = new URL(requestHeader.getUrl());
final HttpURLConnection connectionHttp = (HttpURLConnection) url.openConnection();
connectionHttp.setRequestMethod(requestHeader.getType());
// Send response back to client
final DataInputStream dis = new DataInputStream(connectionHttp.getInputStream());
// Add response header
final StringBuilder sb = new StringBuilder();
sb.append(requestHeader.getHttpVersion() + " " + connectionHttp.getResponseCode() + " "
+ connectionHttp.getResponseMessage() + "\r\n");
final Map<String, List<String>> map = connectionHttp.getHeaderFields();
for (final Map.Entry<String, List<String>> entry : map.entrySet()) {
final String key = entry.getKey();
sb.append(key + " : "
+ entry.getValue().toString().replace("[", "").replace("]", "").replace(",", " ") + "\r\n");
}
sb.append("\r\n");
// Add response content
final DataOutputStream socketOutput = new DataOutputStream(this.socket.getOutputStream());
socketOutput.write(sb.toString().getBytes(), 0, sb.toString().getBytes().length);
final byte[] data = new byte[(int) Short.MAX_VALUE];
int index = dis.read(data, 0, (int) Short.MAX_VALUE);
while (index != -1) {
socketOutput.write(data, 0, index);
index = dis.read(data, 0, (int) Short.MAX_VALUE);
}
socketOutput.flush();
// NOTE this works perfectly fine for HTTP sites. We can intercept the communication properly.
} else if ("CONNECT".equals(requestHeader.getType())) {
// TODO establish connection
// First line of header: CONNECT www.facebook.com:443 HTTP/1.1
// We have tried to send back 200 ok response, but no further requests were sent.
} else {
//Nothing else is supported
return;
}
} catch (final MalformedURLException e) {
System.out.print("MalformedURLException " + e.getMessage());
// return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
} catch (final IOException e) {
System.out.print("IOException " + e.getMessage());
// return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
} finally {
System.out.println("Finished.");
}
}
HTTPComponents supports HTTPS. Also, you don't have to write the socket logic yourself, so there's that.
If I recall right, HTTPS works out of the box, no need for any odd configuration or special ssl calls.
I'am trying to implement a simple HTTP/1.1 client application against a remote HTTP server. If I have a 301 Moved Permanently response from server, I will try to download the file from it's new location given in server's response. I am able to send first GET message to server and retrieve the new URL where the file I asked was moved.
The problem is that when I send second GET request from my client with new location of the file, server returns null. Not sure if anything goes wrong with writing the client message or reading the server response. Here is my code, any help is appreciated.
else if(serverMessage.equals("HTTP/1.1 301 Moved Permanently"))
{
System.out.println(" A new permanent URL is assigned to the file " + fileName);
serverMessage="";
lineCount=0;
while((serverMessage = reader.readLine()) != null)
{
lineCount++;
System.out.println("reply: " + serverMessage);
if(serverMessage.indexOf("Location") >= 0 )
{
for(int x=serverMessage.indexOf("Location")+10; x<serverMessage.length(); x++)
{
newURL= newURL + serverMessage.charAt(x);
}
}
}
System.out.println("newURL : " + newURL);
host = findHost(newURL);
path = findPath(newURL);
fileName=findFileName(newURL);
clientMessage = "GET ";
clientMessage = clientMessage + path;
clientMessage = clientMessage + " HTTP/1.1\r\nHost: ";
clientMessage = clientMessage + host;
clientMessage = clientMessage + "\r\n\r\n";
System.out.println("client message: \"" + clientMessage +"\"");
writer.newLine();
writer.write(clientMessage);
writer.flush();
serverMessage = reader.readLine();
System.out.println("reply2: " + serverMessage); //returns null!!!
while((serverMessage=reader.readLine())!=null)
{
System.out.println("reply2: " + serverMessage);
}
}
EDIT: Variables of client message are the followings (they all work correctly, tested for existing file - successfully downloaded!)
newURL : http://wlab.cs.bilkent.edu.tr/~cs421/pa1/302-redirect-success.txt
host2: wlab.cs.bilkent.edu.tr
path2: /~cs421/pa1/302-redirect-success.txt
fileName2: 302-redirect-success.txt
Are you using a persistent URLConnection / HttpURLConnection?
You may be receiving null if the connection has been closed by the server.
If you are using persistent connections, the server might have not had the time to respond.
This might describe the problem a little better. Check out the timeout given in doHttpUrlConnectionAction(String desiredUrl). You might find the answer there.
If this is your problem, you can try to do multiple reads at 0.1 second intervals for say ... 1-5 seconds. This is to make sure you get the response fast and don't have to wait the full timeout to make sure that the server has responded.