Downloading a picture.

Hello poeple,

I've trying to download a picture via my programm for some days.
I don't know what to do any more.

Here is the code I use:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void downloadFile( string server, string file )
{
    Socket client;
    client.create();
    client.connect(server, 80);
    client.send("GET " +  file + " HTTP/1.1\r\n");
    client.send("Host: " + server + "\r\n\r\n");

    char* response = new char[1024];
    char* wholeFile = new char [30308]; // length of the file.

    client.c_recv(*response);//Header-Teil

    for(short i=0; i<=(30308/1024); i++){
        memset(response, 0, strlen(response)+1);
        client.c_recv(*response);
        strncat(wholeFile, response, strlen(response)+1);
    }

    delete [] response;

    ofstream nFile("image.png", std::ios::out | std::ios::binary | std::ios::ate );
    nFile.write(wholeFile, strlen(wholeFile)+1);

    delete [] wholeFile;
}


There comes an unknown image, it can't be opened.
I hope you can help me.

Thanks in advance,
Kmitska
Last edited on
You can't use C string functions like strlen on binary data.
Nor can you expect an image viewer to open it when it still contains the HTTP header.

Also, what is c_recv, why does it have a char parameter and how is it supposed to know the buffer size?
Last edited on
Here is c_recv;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int Socket::c_recv ( char& s ) const {
  char buf [ MAXRECV + 1 ];
  s = 0;
  memset ( buf, 0, MAXRECV + 1 );

  int status = ::recv ( m_sock, buf, MAXRECV, 0 );
  if ( status > 0 || status != -1 ) {
     memcpy(&s, &buf, strlen(buf)+1);
     return status;
  }
  else {
     throw SockExcept("Fehler in Socket::recv");
     return 0;
  }
}
Unless MAXRECV is 1024 or smaller, you'll get buffer overflows. And even if it is smaller, recv reads as many bytes as currently available up to MAXRECV, so calling recv 30 times won't do.
And again, binary data can contain null bytes, so you cannot use functions like strlen.
The return 0; in line 13 will never be executed, by the way.
I strongly suggest you to use libcurl for this kind of things, unless you try to understand HTTP protocol:
http://curl.haxx.se/
Ok people... here is my latest source, I almost got it but it still doesn't work...:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 void downloadFile( string server, string file )
{
    Socket client;
    client.create();
    client.connect("airtrake.square7.ch", 80);
    client.send("GET /webseite/community.PNG HTTP/1.1\r\n");
    client.send("Host: www.airtrake.square7.ch\r\n\r\n");

    int len = 0;
    char* response = new char[1024];
    len = client.c_recv(response);

    ofstream nFile("image.png", std::ios::out | std::ios::binary | std::ios::ate );

    int endLines = 0;
    for(int n=0; n<=len; n++){
        if(response[n] == '\n'){
            endLines++;
            if(endLines == 9){
                endLines = n;
                break;
            }
        }
    }
    char* tmp = new char[len-endLines];
    memcpy(tmp, response+endLines+1, len-endLines );
    nFile.write(tmp, len-endLines );
    delete [] tmp;
    for(short i=0; i<=(30308/1024)+5; i++){
        memset(response, 0, 1024);
        len = client.c_recv(response);
        cout << len << endl;
        nFile.write(response, len );
    }
    delete [] response;
} 


and here is c_recv():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 int Socket::c_recv ( char* s ) const {
  char buf [ MAXRECV  ];
  memset ( buf, 0, MAXRECV );

  size_t len = ::recv ( m_sock, buf, MAXRECV, 0 );
  if ( len > 0 ) {
     memcpy( s, buf, len);
     return len;
  }
  else {
     throw SockExcept("Fehler in Socket::recv");
     return 0;
  }
} 


Can anyone help me? :)
recv gives you as many bytes as are currently available, so you cannot call recv a fixed number of times as with:
for(short i=0; i<=(30308/1024)+5; i++){
You need to receive until all data arrived or the connection is terminated.

You're writing one byte too much in line 27.

And of course, you cannot assume that the HTTP header will always consist of 8 lines, nor can you assume that it will be complete after just one call to recv.

The issue with the buffer size remains as well - either you need to tell c_recv your buffer size or the buffer needs to be of size MAXRECV (or greater).
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void downloadFile( string server, string file )
{
    Socket client;
    client.create();
    client.connect("airtrake.square7.ch", 80);
    client.send("GET /webseite/community.PNG HTTP/1.1\r\n");
    client.send("Host: www.airtrake.square7.ch\r\n\r\n");

    int len = 0;
    char* response = new char[1024];
    len = client.c_recv(response);

    ofstream nFile("image.png", std::ios::out | std::ios::binary | std::ios::ate );

    int endLines = 0;
    for(int n=0; n<=len; n++){
        if(response[n] == '\n'){
            endLines++;
            if(endLines == 9){
                endLines = n;
                break;
            }
        }
    }
    char* tmp = new char[len-endLines];
    memcpy(tmp, response+endLines+1, len-endLines );
    nFile.write(tmp, len-endLines-1 );
    delete [] tmp;
    for(short i=0; i<=(30308/1024)+1; i++){
        memset(response, 0, 1024);
        len = client.c_recv(response);
        cout << len << endl;
        nFile.write(response, len );
    }
    delete [] response;
}


It's looking now like this, and almost done. Only a part of the end doesn't appear.
And what do you mean with the last part?
The issue with the buffer size remains as well - either you need to tell c_recv your buffer size or the buffer needs to be of size MAXRECV (or greater).
Hello again people,

I've made now the normal saving thing.
Now I want to keep it in RAM, I've made this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
void downloadFile( string server, string file )
{
    Socket client;
    client.create();
    client.connect(server, 80);
    client.send("GET " + file + " HTTP/1.1\r\n");
    client.send("Host: "+  server + "\r\n\r\n");

    int len = 0;
    char* response = new char[1024];
    len = client.c_recv(response);

    int endLines = 0;
    for(;;)
    {
        char* point = (char*) memchr(response+endLines+1, '\r', len);
        int pos = point-response;
        endLines = pos;
        if(response[pos+1] == '\n' && response[pos+2] == '\r' && response[pos+3] == '\n')
        {
            break;
        }
    }

    char* htmp = new char[endLines];
    memcpy(htmp, response, endLines);
    string header(htmp);
    delete [] htmp;

    int found = header.find("Content-Length: ");
    for(int n=found+15; n<=endLines; n++){
        if(header[n] == '\n'){
            header.erase(n,endLines);
            header.erase(0,found+16);
            break;
        }
    }
    stringstream ss;
    ss << header;
    size_t fileSize;
    ss >> fileSize;
    size_t downloaded = 0;

    char* wholeContent = new char [fileSize];

    char* tmp = new char[len-endLines];
    memcpy(tmp, response+endLines+4, len-endLines );
    memcpy(wholeContent, tmp, len-endLines );
    delete [] tmp;

    downloaded += len-endLines+1;

    while ( downloaded < fileSize )
    {
        memset(response, 0, 1024);
        len = client.c_recv(response);
        memcpy(wholeContent+downloaded+1, response, len);
        downloaded+=len;
    }
    delete [] response;

    ofstream nFile("image.png", std::ios::out | std::ios::binary | std::ios::ate );
    nFile.write(wholeContent, fileSize);
    nFile.close();

    delete [] wholeContent;
}
]


The problem is now the same one: The picture isn't completely.
Last edited on
Topic archived. No new replies allowed.