I have a (pretty ugly) method that gets a page from a website and all the images on the page. Fetching the webpage is no problem at all. But when I fetch the images, they come out all weird and definitly not as they where sent. The uri I have been using for testing is this: http://www.themountaingoats.net/contact.html This webpage is very simple and has everything I need for testing.
Using \r or \n as an endline character gives different results and \r\n makes it impossible to even open the images.
public static String GET(String uri, int port) throws IOException {
String domain = uri.split("/",2)[0];
String filename = uri.split("/",2)[1];
Socket socket = new Socket(domain, port);
// send the command to the server.
System.out.println(socket.isConnected());
DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String request = "GET " +"/"+ filename + " HTTP/1.1 "+"\r\n"+"Host: " + domain + "\r\n\r\n";
System.out.println(request);
outToServer.writeBytes(request);
//create a file to write in.
File file = new File(domain+".txt");
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
PrintWriter writer = new PrintWriter(file);
writer.print("");
writer.close();
int characterCounter=100;
while(characterCounter >= 0){
String serverSentence = inFromServer.readLine();
System.out.println(serverSentence);
if (serverSentence.startsWith("Content-Length:")){
characterCounter = Integer.parseInt(serverSentence.replace("Content-Length: ",""));
}
if ( !serverSentence.startsWith("Cache-Control: ") && !serverSentence.startsWith("Content-Type: ") && !serverSentence.startsWith("Date: ") && !serverSentence.startsWith("Etag: ")
&& !serverSentence.startsWith("Expires: ") && !serverSentence.startsWith("Last-Modified: ") && !serverSentence.startsWith("Server: ") && !serverSentence.startsWith("Vary: ")
&& !serverSentence.startsWith("X-Cache: ") && !serverSentence.startsWith("Content-Length: ") ){
characterCounter = characterCounter - serverSentence.length()-1;
}
//write in the file
FileWriter fw = new FileWriter(file.getAbsoluteFile(),true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(serverSentence+"\r\n");
bw.close();
}
Document doc = Jsoup.parse(file, "UTF-8");
Elements imgs = doc.getElementsByTag("img");
System.out.println(imgs);
for (Element link : imgs) {
String source = link.attr("src");
source = source.replace("http://"+domain+"", "");
System.out.println(source);
//create a file to write in.
File image = new File(source.replace("/", "."));
// if file doesnt exists, then create it
if (!image.exists()) {
image.createNewFile();
}
PrintWriter imageWriter = new PrintWriter(image);
imageWriter.print("");
imageWriter.close();
String requestImage = "GET "+ source + " HTTP/1.1 "+"\r\n"+"Host: " + domain + "\r\n\r\n";
System.out.println(requestImage);
outToServer.writeBytes(requestImage);
boolean flag = false;
String previousServerSentence = "something not empty";
characterCounter=100;
while(characterCounter > 0){
String serverSentence = inFromServer.readLine();
System.out.println(serverSentence);
if (serverSentence.startsWith("Content-Length:")){
characterCounter = Integer.parseInt(serverSentence.replace("Content-Length: ",""));
}
if (!flag){
if ( previousServerSentence.matches("") && !serverSentence.matches("")){
flag = true;
}
}
if ( (!serverSentence.startsWith("Cache-Control: ") && !serverSentence.startsWith("Content-Type: ") && !serverSentence.startsWith("Date: ") && !serverSentence.startsWith("Etag: ")
&& !serverSentence.startsWith("Expires: ") && !serverSentence.startsWith("Last-Modified: ") && !serverSentence.startsWith("Server: ") && !serverSentence.startsWith("Vary: ")
&& !serverSentence.startsWith("X-Cache: ") && !serverSentence.startsWith("Content-Length: ") && !serverSentence.startsWith("ETag: ") && !serverSentence.startsWith("Accept-Ranges: ")
&& !serverSentence.startsWith("Accept-Language: ") && !serverSentence.startsWith("Accept-Datetime: ") && !serverSentence.startsWith("Authorization: ")
&& !serverSentence.startsWith("Connection: ") && !serverSentence.startsWith("Content-Language: ") && !serverSentence.startsWith("Content-Length: ")
&& !serverSentence.startsWith("Content-Location: ") && !serverSentence.startsWith("Content-MD5: ") && !serverSentence.startsWith("Content-Range: ")
&& !serverSentence.startsWith("Content-Type: ") && !serverSentence.startsWith("Date: ") && !serverSentence.startsWith("expect: ")
&& !serverSentence.startsWith("From: ") && !serverSentence.startsWith("Host: ") && !serverSentence.startsWith("If-Match: ") && !serverSentence.startsWith("If-Modified-Since: ")
&& !serverSentence.startsWith("Accept: ") && !serverSentence.startsWith("Accept-Charset: ") && !serverSentence.startsWith("Accept-Encoding: ")
&& !serverSentence.startsWith("Age: ") && !serverSentence.startsWith("Allow: ") && !serverSentence.startsWith("Content-Encoding: ")
&& !serverSentence.startsWith("If-None-Match: ") && !serverSentence.startsWith("If-Range: ") && !serverSentence.startsWith("If-Unmodified-Since: ")
&& !serverSentence.startsWith("Last-Modified: ") && !serverSentence.startsWith("Location: ") && !serverSentence.startsWith("Max-Forwards: ")
&& !serverSentence.startsWith("Pragma: ") && !serverSentence.startsWith("Proxy-Authenticate: ") && !serverSentence.startsWith("Proxy-Authorization: ")
&& !serverSentence.startsWith("Range: ") && !serverSentence.startsWith("Referer: ") && !serverSentence.startsWith("Retry-After: ")
&& !serverSentence.startsWith("Server: ") && !serverSentence.startsWith("TE: ") && !serverSentence.startsWith("Trailer: ")
&& !serverSentence.startsWith("Transfer-Encoding: ") && !serverSentence.startsWith("Upgrade: ") && !serverSentence.startsWith("User-Agent: ")
&& !serverSentence.startsWith("Via: ") && !serverSentence.startsWith("Warning: ") && !serverSentence.startsWith("WWW-Authenticate: "))
&& flag){
characterCounter = characterCounter - serverSentence.length()-1;
//write in the file
FileWriter fw = new FileWriter(image.getAbsoluteFile(),true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(serverSentence+"\r");
bw.close();
}
previousServerSentence = serverSentence;
}
}
return null;
}
The first image is for \r as endline, the second image is for \n as endline and the last image is the original one. I have absolutely no clue as to why the images get fucked up so bad.
So my question is: Why does this happen and how do I fix it?
EDIT:
public static String GET(String uri, int port) throws IOException {
/*
* Retrieval of the webpage
*/
String domain = uri.split("/",2)[0];
String filename = uri.split("/",2)[1];
Socket socket = new Socket(domain, port);
// send the command to the server.
System.out.println(socket.isConnected());
DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String request = "GET " +"/"+ filename + " HTTP/1.1 "+"\r\n"+"Host: " + domain + "\r\n\r\n";
System.out.println(request);
outToServer.writeBytes(request);
//create a file to write in.
File file = new File(domain+".txt");
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
PrintWriter writer = new PrintWriter(file);
writer.print("");
writer.close();
int characterCounter=100;
while(characterCounter >= 0){
String serverSentence = inFromServer.readLine();
System.out.println(serverSentence);
if (serverSentence.startsWith("Content-Length:")){
characterCounter = Integer.parseInt(serverSentence.replace("Content-Length: ",""));
}
if ( !serverSentence.startsWith("Cache-Control: ") && !serverSentence.startsWith("Content-Type: ") && !serverSentence.startsWith("Date: ") && !serverSentence.startsWith("Etag: ")
&& !serverSentence.startsWith("Expires: ") && !serverSentence.startsWith("Last-Modified: ") && !serverSentence.startsWith("Server: ") && !serverSentence.startsWith("Vary: ")
&& !serverSentence.startsWith("X-Cache: ") && !serverSentence.startsWith("Content-Length: ") ){
characterCounter = characterCounter - serverSentence.length()-1;
}
//write in the file
FileWriter fw = new FileWriter(file.getAbsoluteFile(),true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(serverSentence+"\r\n");
bw.close();
}
/*
* Retrieval of all the embedded images on the webpage that are on the same domain.
*/
Document doc = Jsoup.parse(file, "UTF-8");
Elements imgs = doc.getElementsByTag("img");
System.out.println(imgs);
for (Element link : imgs) {
String source = link.attr("src");
source = source.replace("http://"+domain+"", "");
System.out.println(source);
//create a file to write in.
File image = new File(source.replace("/", "."));
// if file doesnt exists, then create it
if (!image.exists()) {
image.createNewFile();
}
// Initialize the streams.
final FileOutputStream fileOutputStream = new FileOutputStream(image);
final InputStream inputStream = socket.getInputStream();
// Header end flag.
boolean headerEnded = false;
String requestImage = "GET "+ source + " HTTP/1.1 "+"\r\n"+"Host: " + domain + "\r\n\r\n";
System.out.println(requestImage);
outToServer.writeBytes(requestImage);
int buffersize = 1000000;
byte[] bytes = new byte[buffersize];
int length;
while ((length = inputStream.read(bytes)) != -1) {
// If the end of the header had already been reached, write the bytes to the file as normal.
if (headerEnded){
fileOutputStream.write(bytes, 0, length);
}
// This locates the end of the header by comparing the current byte as well as the next 3 bytes
// with the HTTP header end "\r\n\r\n" (which in integer representation would be 13 10 13 10).
// If the end of the header is reached, the flag is set to true and the remaining data in the
// currently buffered byte array is written into the file.
else {
for (int i = 0; i < buffersize-3; i++) {
if (bytes[i] == 13 && bytes[i + 1] == 10 && bytes[i + 2] == 13 && bytes[i + 3] == 10) {
headerEnded = true;
fileOutputStream.write(bytes, i+4 , buffersize-i-4);
break;
}
}
}
}
inputStream.close();
fileOutputStream.close();
}
socket.close();
return null;
}
This is my result now:
I can get part of the picture, but not the entire picture. Playing with the buffersize gets me a little further or even a little less far.
EDIT2: I found the error. It just had to do with some dimensions. Final working code:
public static String GET(String uri, int port) throws IOException {
/*
* Retrieval of the webpage
*/
String domain = uri.split("/",2)[0];
String filename = uri.split("/",2)[1];
Socket socket = new Socket(domain, port);
// send the command to the server.
System.out.println(socket.isConnected());
DataOutputStream outToServer = new DataOutputStream(socket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String request = "GET " +"/"+ filename + " HTTP/1.1 "+"\r\n"+"Host: " + domain + "\r\n\r\n";
System.out.println(request);
outToServer.writeBytes(request);
//create a file to write in.
File file = new File(domain+".txt");
// if file doesnt exists, then create it
if (!file.exists()) {
file.createNewFile();
}
PrintWriter writer = new PrintWriter(file);
writer.print("");
writer.close();
int characterCounter=100;
while(characterCounter >= 0){
String serverSentence = inFromServer.readLine();
System.out.println(serverSentence);
if (serverSentence.startsWith("Content-Length:")){
characterCounter = Integer.parseInt(serverSentence.replace("Content-Length: ",""));
}
if ( !serverSentence.startsWith("Cache-Control: ") && !serverSentence.startsWith("Content-Type: ") && !serverSentence.startsWith("Date: ") && !serverSentence.startsWith("Etag: ")
&& !serverSentence.startsWith("Expires: ") && !serverSentence.startsWith("Last-Modified: ") && !serverSentence.startsWith("Server: ") && !serverSentence.startsWith("Vary: ")
&& !serverSentence.startsWith("X-Cache: ") && !serverSentence.startsWith("Content-Length: ") ){
characterCounter = characterCounter - serverSentence.length()-1;
}
//write in the file
FileWriter fw = new FileWriter(file.getAbsoluteFile(),true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(serverSentence+"\r\n");
bw.close();
}
/*
* Retrieval of all the embedded images on the webpage that are on the same domain.
*/
Document doc = Jsoup.parse(file, "UTF-8");
Elements imgs = doc.getElementsByTag("img");
System.out.println(imgs);
for (Element link : imgs) {
// Getting the link ready for GET query.
String source = link.attr("src");
source = source.replace("http://"+domain+"", "");
System.out.println(source);
//create a file to write in.
File image = new File(source.replace("/", "."));
// if file doesnt exists, then create it
if (!image.exists()) {
image.createNewFile();
}
String requestImage = "GET "+ source + " HTTP/1.1 "+"\r\n"+"Host: " + domain + "\r\n\r\n";
System.out.println(requestImage);
outToServer.writeBytes(requestImage);
// Initialize the streams.
final FileOutputStream fileOutputStream = new FileOutputStream(image);
final InputStream inputStream = socket.getInputStream();
// Header end flag.
boolean headerEnded = false;
int buffersize = 10000;
byte[] bytes = new byte[buffersize];
int length;
while ((length = inputStream.read(bytes)) != -1) {
// If the end of the header had already been reached, write the bytes to the file as normal.
if (headerEnded){
fileOutputStream.write(bytes, 0, length);
}
// This locates the end of the header by comparing the current byte as well as the next 3 bytes
// with the HTTP header end "\r\n\r\n" (which in integer representation would be 13 10 13 10).
// If the end of the header is reached, the flag is set to true and the remaining data in the
// currently buffered byte array is written into the file.
else {
for (int i = 0; i < length-3; i++) {
if (bytes[i] == 13 && bytes[i + 1] == 10 && bytes[i + 2] == 13 && bytes[i + 3] == 10) {
headerEnded = true;
fileOutputStream.write(bytes, i+4 , length-i-4);
break;
}
}
}
}
inputStream.close();
fileOutputStream.close();
}
socket.close();
return null;
}
Avoid using raw socket to process http request when possible.
See 4ndrew's answer if you can use a seperate connection to retrive image file: https://stackoverflow.com/a/8679160/176873
If you are stuck with raw sockets, then avoid using java.io.BufferedReader. BufferedReader should not be used to read binary data. You are converting binary data to String and writing a text file to your local pc.
See Alexay's answer for a workaround: https://stackoverflow.com/a/34106534/176873