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);
}
Related
I have simple http server on android from Android Samples. I like this server, so I also want to recive POST data from browser. How can I recive it with standart things (without external libraries) ? I try to recive it like GET, but js console show connection error.
private void handle(Socket socket) throws IOException {
BufferedReader reader = null;
PrintStream output = null;
try {
String route = null;
// Read HTTP headers and parse out the route.
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while (!TextUtils.isEmpty(line = reader.readLine())) {
if (line.startsWith("GET /")) {
int start = line.indexOf('/') + 1;
int end = line.indexOf(' ', start);
route = line.substring(start, end);
break;
}
}
// Output stream that we send the response to
output = new PrintStream(socket.getOutputStream());
// Prepare the content to send.
if (null == route) {
writeServerError(output);
return;
}
byte[] bytes = loadContent(route);
if (null == bytes) {
writeServerError(output);
return;
}
// Send out the content.
output.println("HTTP/1.0 200 OK");
output.println("Content-Type: " + detectMimeType(route));
output.println("Content-Length: " + bytes.length);
output.println();
output.write(bytes);
output.flush();
} finally {
if (null != output) {
output.close();
}
if (null != reader) {
reader.close();
}
}
}
full code
In general the http request is a text fragment. The type of the request is indicated in the text. So in a GET request the example you provide first finds the "GET" string. Then parses the get request. The same should be done for POST. First identify the "POST" then parse the rest of the request.
I would send a XML file splitted into N parts in my server side.
Each files contains at start this informations : fileNumber and totalPart
For example if I have 32 parts :
- the first file contain at start : 0 (file number) and 32 (total parts)
- the second file contain at start : 1 (file number) and 32 (total parts)...
With a for loop, I can send all the parts in the same time to my client.
But my client can't receive all the parts, I lost some parts..
How I can process for requested the missing parts ?
This is my server side code :
for (int i = 0; i < nbPart + 1; i++) {
File f = null;
BufferedReader br = null;
String content = "";
byte[] sendBuffer = null;
try {
f = new File("xml/file.part" + i);
br = new BufferedReader(new FileReader(f));
StringBuilder sbuilder = new StringBuilder();
String line = br.readLine();
while (line != null) {
sbuilder.append(line);
line = br.readLine();
if (line != null) {
sbuilder.append("\n");
}
}
content = i + ";" + nbPart + "#tag#" + sbuilder.toString();
int total = new Long(f.length()).intValue();
sendBuffer = new byte[total];
sendBuffer = content.getBytes();
DatagramSocket sendSocket = new DatagramSocket();
DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, source, PORT_SEND);
sendSocket.send(sendPacket);
sendSocket.close();
Thread.sleep(timeToSend);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null)
br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
And this is my client side code :
while (run) {
DatagramSocket receiveSocket = null;
DatagramPacket receivePacket = null;
data = "";
byte[] receiveBuffer = new byte[9999];
Arrays.fill(receiveBuffer, (byte) 0);
try {
receiveSocket = new DatagramSocket(PORT_RECEIVE);
receivePacket = new DatagramPacket(receiveBuffer,receiveBuffer.length);
receiveSocket.receive(receivePacket);
receiveSocket.close();
data = new String(receiveBuffer, receivePacket.getOffset(), receivePacket.getLength());
String datas[] = data.split("#tag#");
String dataParts[] = datas[0].split(";");
int numPart = Integer.parseInt(dataParts[0]);
totalPart = Integer.parseInt(dataParts[1]);
if(partReceive.isEmpty()){
for(int i=0;i<totalPart+1;i++){
partReceive.add(Boolean.FALSE);
}
}
File part = new File(filePath+"/file.part"+numPart);
if(part.exists()) part.delete();
writeToFile(part, datas[1]);
partReceive.set(numPart, Boolean.TRUE);
Log.wtf("Part"+numPart, partReceive.get(numPart).toString());
} catch (Exception e) {
e.printStackTrace();
}
}
As you can see, my first idea is : In client side, I create an ArrayList partReceive who contains boolean (False), when I receive a part, I set the index of the ArrayList to "True". But after How I can process ?
Two possibles ways that come to my mind:
Use TCP. It automatically ensures that all packets are received in order.
Maybe you deliberately want you use UDP. I don't quite understand the sense of your ArrayList partReceive. The loop will alawys set all elements false, as totalPart is constant throughout a transfer. In your example it will always be 32. I would rather assign an ID to each packet. An ID is a unique number. You could use numPart for example. When receiving a packet, store its ID in a list. After the entire transmission finished, check what ids are still missing. The easiest approach then would be to request each missing packet.
Something like that
ArrayList<Integer> receivedParts = new ArrayList<Integer>();
// save id of received packet
receivedParts.add(numPart);
// ...
// after transmission has finished
// Keep in mind that packets do not necessarily need to arrive in the same order like you've sent them when using UDP.
ArrayList<Integer> missingIDs = getMissingIDs(receivedParts);
for(Integer currentID : missingIDs) {
// request missing packets
requestMissingPacket(currentID);
}
There are different ways to check whether the tranmission has finished:
After having received all packets, the transmission. Just check the size of your receiveParts list.
Use a timeout. For example if you don't receive any packet during x seonds, consider the tranmission finished. Then check what packets are missing.
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.
It seems that using curl and most web browsers my server code is closing the connection before the client is able to read the response. Here is my code
public void run() {
try {
InputStream input = clientSocket.getInputStream();
OutputStream output = clientSocket.getOutputStream();
System.out.println(input);
// getRequestObject(input);
long time = System.currentTimeMillis();
output.write(("HTTP/1.1 200 OK\n\nWorkerRunnable: " + this.serverText + " - " + time + "").getBytes());
output.flush();
output.close();
input.close();
System.out.println("Request processed: " + time);
} catch (IOException e) {
// report exception somewhere.
e.printStackTrace();
}
}
protected String readInputStream(InputStream input) throws IOException {
String inputLine;
BufferedReader in = new BufferedReader(new InputStreamReader(input));
StringBuilder sb = new StringBuilder();
while (!(inputLine = in.readLine()).equals("")) {
sb.append(inputLine);
}
return sb.toString();
}
Any thoughts?
Perhaps the problem could be caused by the fact that you're not reading the client's data. The client is trying to send you HTTP headers, but you immediately start sending the response. Try reading from the InputStream until you receive an empty line (which signals the end of the request HTTP headers) and then start sending the output.
If you need to embed an HTTP server in your application, I strongly recommend you to use an existing library. Implementing your own HTTP compliant server is going to be tedious work. See
Create a simple HTTP server with Java?
NanoHTTPD
(This is for a signed applet and I have decided against HTTPClient to keep my jar very small)
I am using HttpURLConnection to successfully upload a file from the user to a server using multi-part form post.
The problem is that HttpURLConnection is caching the data -- before sending it. So when I am reading from the file and writing to Outputstream, it is merely buffering the data -- and therefore my progress bar, that shows the upload status , is completely wrong. Howevere please note that the form post code works and the file does get uploaded correctly with return code of 200.
So how do I ensure that HttpURLConnection does not cache the data that I am sending to the server ?
Here is my source:
public UploadResponse send(String formPostUrlStr,String fileFieldName,File targetFile, Map<String, String> valuesMap, UploadStatusListener uploadStatusListener) throws Exception{
String sendStr=getBoundaryMessage(Boundary, valuesMap, fileFieldName, targetFile.getName(), valuesMap.get("content-type") );//"image/png") ;
System.out.println(" multi-part start \n "+ sendStr+ " multi-part end \n");
String lenstr=Long.toString((long)(sendStr.length()*2)+ targetFile.length());
System.out.println("Content-Length"+ lenstr);
//Content-Length
URL url= new URL(formPostUrlStr);
long startTime= System.currentTimeMillis();
HttpURLConnection s3Connection = (HttpURLConnection) url.openConnection();
System.out.println("opened url to "+ formPostUrlStr +", connection ok ..");
s3Connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="
+ Boundary);
s3Connection.setRequestProperty("content-length", lenstr);
s3Connection.setDoOutput(true);
s3Connection.setDoInput(true);
s3Connection.setUseCaches(false);
s3Connection.setInstanceFollowRedirects(true);
s3Connection.setAllowUserInteraction(true);
s3Connection.setRequestProperty("User-Agent", "Mozilla/4.5");
if (uploadStatusListener != null) {
uploadStatusListener.statusUpdate(targetFile.length(), 0);
}
String debugStr= s3Connection.toString();
System.out.println("conmnection "+ debugStr);
DataOutputStream httpOut = new DataOutputStream(s3Connection.getOutputStream());
System.out.println("opened DataOutputStream ok ..");
httpOut.write(sendStr.getBytes());
//httpOut.flush();
System.out.println("httpOut.flush 1 ok ..");
FileInputStream uploadFileReader = new FileInputStream(targetFile);
long totalBytes = uploadFileReader.available();
if (uploadStatusListener != null) {
uploadStatusListener.statusUpdate(totalBytes, 0);
}
System.out.println(" uploading file with size "+ uploadFileReader.available());
int bufSize = 102400;
long availableBytesToRead;
long totalSent = 0;
while ((availableBytesToRead = uploadFileReader.available()) > 0) {
byte[] bufferBytesRead;
bufferBytesRead = availableBytesToRead >= bufSize ? new byte[bufSize]
: new byte[(int)availableBytesToRead];
int count = uploadFileReader.read(bufferBytesRead);
try{
httpOut.write(bufferBytesRead);
totalSent += ((long) count);
System.out.println(" wrote bytes = "+count+ ", total sent = "+ totalSent +", pendingSize"+ (availableBytesToRead-count) );
}
catch(IOException ioe){
System.out.println(" io exceotion e"+ ioe.getMessage());
throw ioe;
}
//httpOut.flush();
if (uploadStatusListener != null) {
uploadStatusListener.statusUpdate(totalBytes, totalSent);
}
}
// FILE DATA END
httpOut.write(("--" + Boundary + "--\r\n").getBytes());
// form end
httpOut.write(("--" + Boundary + "--\r\n").getBytes());
httpOut.flush();
httpOut.close();
long endTime= System.currentTimeMillis();
System.out.println("Completed Writing Data to S3 Connection in "+ (endTime-startTime)+"ms.,now waiting for rsponse code ");
int code=s3Connection.getResponseCode();
long endTime2= System.currentTimeMillis();
System.out.println("Completed Sendind Data to S3 in "+ (endTime2-startTime)+ "ms., rsponse code time "+ (endTime2-endTime)+"ms. ");
UploadResponse uploadResponse = new UploadResponse();
uploadResponse.setCode(code);
System.out.println(" response code : " + code);
StringBuilder response = new StringBuilder();
byte[] respBuffer = new byte[4096];
if (code > 300) {
if (code == 404) {
throw new Exception("Error 404");
}
BufferedReader err = new BufferedReader(
new InputStreamReader(s3Connection.getErrorStream()));
String ret;
StringBuffer buff = new StringBuffer();
while ((ret = err.readLine()) != null) {
buff.append(ret);
}
uploadResponse.setMessage(buff.toString());
System.out.println(" error :"+ buff.toString());
err.close();
} else {
BufferedReader inp = new BufferedReader(
new InputStreamReader(s3Connection.getInputStream()));
StringBuffer buff = new StringBuffer();
String ret;
while ((ret = inp.readLine()) != null) {
buff.append(ret);
}
inp.close();
uploadResponse.setMessage(buff.toString());
if(buff.toString().contains("fail"))
throw new Exception("Upload failed");
}
System.out.println(response.toString());
return uploadResponse;
}
}
I have the same problem.
I didn't find any other solution than writing my HTTP request on a raw Socket.
Did you find a better workaround ?
EDIT : I just did : we just have to use obj.setFixedLengthStreamingMode(12345) on the HttpURLConnection object obtained from url.openConnection(), where 12345 is the length of POST request body.
As a complementation for the answer that #Antares gave, there is another method setChunkedStreamingMode that is used when you don't know the content size in advance. So when you do a POST request, call that method on the connection:
HttpURLConnection connection = ...
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setChunkedStreamingMode(0);
connection.connect();
... connection.getOutputStream();
This will avoid the OutputStream to buffer the entire content before start to send.