Download a file using http & winsock
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15

Thread: Download a file using http & winsock

  1. #1
    Join Date
    Sep 2004
    Location
    this
    Posts
    115

    Question Download a file using http & winsock

    i'm trying to write a program that sends an http request to a server, and downloads a binary file. don't want to use wininet.dll functions b/c i'm already familiar with this method.

    the program syntax will be:

    httpget someserver.com /thefolder/thefile.zip c:\thefile.zip

    i have not started the recv() part yet, b/c i am a bit confused on what to do next.

    is my code ok so far?

    here is what i have:

    Code:
    #include <string>
    #include <stdio.h>
    #include <winsock2.h>
    using std::string;
    int main(int argc, char **argv)
    {
        char buf[1024];
        FillMemory(buf,1024,0x0);
        string request;
        int sendret;
        int recvret;
        const char lb[]="\x0a\x0d\x0a\x0d";
        const char http[]="http\x3a//";
        const char snsn[]="%s\n%s\n";
        bool error1=false;
        bool error2=false;
        bool error3=false;
        printf(snsn,lb,"-=[ httpget v1.0 by Avery Tarasov ]=-");
        printf(snsn,"-=[ Email: c0ldshadow@deeptide.com ]=-",lb);
        if(argc!=4)
        {
            printf(snsn,"Correct usage: httpget server.com /folder/file.zip c:\\savehere.zip");
            return 0;
        }
    	WSADATA wsaData;
    	if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
    	{
            printf(snsn,"Error initializing Winsock 2.2");
            return 0;
    	}
        error1=true;
    	if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
    	{
            printf(snsn,"Winsock 2.2 not available");
            goto cleanup;
    	}
        struct hostent *h;
        struct sockaddr_in sa;
        SOCKET server1;
        h=gethostbyname(argv[1]);
        if(h==0)
        {
            printf(snsn,"gethostbyname() failed");
            goto cleanup;
        }
        memcpy((char *)&sa.sin_addr,(char *)h->h_addr,sizeof(sa.sin_addr));
        sa.sin_family=h->h_addrtype;
        sa.sin_port=htons(80);
        server1=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(server1==INVALID_SOCKET)
        {
            printf(snsn,"socket() failed");
            goto cleanup;
        }
        error1=false;
        error2=true;
        if(connect(server1,(struct sockaddr *)&sa,sizeof(sa))<0)
        {
            printf(snsn,"connect() failed");
            goto cleanup;
        }
        request+="GET ";
        request+=argv[1];
        request+=argv[2];
        request+=" HTTP/1.1";
        request+=&lb[2];
        request+="Host :";
        request+=argv[1];
        request+=lb;
        sendret=send(server1,request.c_str(),request.length()+1,0);
        if(sendret==-1)
        {
            printf(snsn,"send() failed");
            goto cleanup;
        }
    
    //think i need recv and a new socket variable to use now.. stuck here a bit
        cleanup:
        if(error1)
        {
            WSACleanup();
        }
        if(error2)
        {
            WSACleanup();
            closesocket(server1);
        }
        return 0;
    }

  2. #2
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: Download a file using http & winsock

    Use HTTP/1.0 instead of 1.1. One main difference is that for 1.0, the server will automatically close the connection after it sends the file. THis will make your program's logic easier, since you can equate closure of the connection with end of file. Another difference is that for 1.1, you would need to support "Chunked" transmission from the server, which unduly complicates your first attempts here.

    The server is not expecting a NULL-terminated string, so just send request.length() not length()+1

    You don't need a new socket for the reception. Just create a decently-sized char buffer and call recv:
    Code:
    #define BUFFER_LEN (4096)
    int iRecv;
    int iResponseLength = 0;
    char recvBuffer[BUFFER_LEN] = {0};
    string response;
    while ( (iRecv = recv( server1, recvBuffer, BUFFER_LEN-1, 0 ) ) > 0 )
    {
      response.append(recvBuffer, iRecv);
      iResponseLength += iRecv;
      zeromemory( recvBuffer, BUFFER_LEN );
    }
    
    if ( iRecv == SOCKET_ERROR )
    {
      // handle the error
    }
    else
    {
      // connection was closed and "response" now contains the
      // response from the server
      // Your file will immediately follow the first double-CRLF
      // iResponseLength will tell you how many bytes were received
      // Note that you cannot use any of the length() functions since the file
      // could possibly contain valid NULL bytes
    }
    Mike
    Last edited by MikeAThon; November 21st, 2006 at 07:20 PM. Reason: to change "+=" to "append"

  3. #3
    Join Date
    Sep 2004
    Location
    this
    Posts
    115

    Re: Download a file using http & winsock

    thanks for the response MikeAThon.

    i got the program working:

    Code:
    #include <string>
    #include <stdio.h>
    #include <winsock2.h>
    #define BUFFER_LEN (4096)
    using std::string;
    int main(int argc, char **argv)
    {
        char buf[1024];
        FillMemory(buf,1024,0x0);
        HANDLE fhand;
        string request;
        int sendret;
        int iRecv;
        int iResponseLength=0;
        int offset;
        DWORD dw;
        string res2;
        char recvBuffer[BUFFER_LEN]={0};
        string response;
        const char lb[]="\r\n\r\n";
        const char http[]="http\x3a//";
        const char snsn[]="%s\n";
        bool error1=false;
        bool error2=false;
        bool error3=false;
        int len3=strlen(argv[3]);
        if(argc!=4)
        {
            printf(snsn,"Correct usage: httpget server.com /folder/file.zip c:\\savehere.zip");
            goto cleanup;
        }
        WSADATA wsaData;
        if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
        {
            printf(snsn,"Error initializing Winsock 2.2");
            goto cleanup;
        }
        error1=true;
        if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
        {
            printf(snsn,"Winsock 2.2 not available");
            goto cleanup;
        }
        struct hostent *h;
        struct sockaddr_in sa;
        SOCKET server1;
        h=gethostbyname(argv[1]);
        if(h==0)
        {
            printf(snsn,"gethostbyname() failed");
            goto cleanup;
        }
        memcpy((char *)&sa.sin_addr,(char *)h->h_addr,sizeof(sa.sin_addr));
        sa.sin_family=h->h_addrtype;
        sa.sin_port=htons(80);
        server1=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(server1==INVALID_SOCKET)
        {
            printf(snsn,"socket() failed");
            goto cleanup;
        }
        error1=false;
        error2=true;
        if(connect(server1,(struct sockaddr *)&sa,sizeof(sa))<0)
        {
            printf(snsn,"connect() failed");
            goto cleanup;
        }
        request+="GET http://";
        request+=argv[1];
        request+=argv[2];
        request+=" HTTP/1.0";
        request+=&lb[2];
        request+="Host: ";
        request+=argv[1];
        request+=lb;
        printf("%s",request.c_str());
        sendret=send(server1,request.c_str(),request.length(),0);
        if(sendret==-1)
        {
            printf(snsn,"send() failed");
            goto cleanup;
        }
    	fhand=CreateFile(argv[3],GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    	if(fhand==INVALID_HANDLE_VALUE)
    	{
            printf(snsn,"CreateFile() failed");
            goto cleanup;
    	}
        error2=false;
        error3=true;
        while((iRecv=recv(server1,recvBuffer,BUFFER_LEN-1,0))>0)
        {
            response.append(recvBuffer,iRecv);
            iResponseLength+=iRecv;
            ZeroMemory(recvBuffer,BUFFER_LEN);
        }
        if(iRecv==SOCKET_ERROR)
        {
            printf(snsn,"recv() failed");
        }
        offset=response.find(lb)+4;
        if(offset!=string::npos)
        {
            res2.assign(response,offset,response.size());
            if(WriteFile(fhand,res2.data(),res2.size(),&dw,0)==0)
            {
                printf(snsn,"WriteFile() failed");
                goto cleanup;
            }
        }
    
    
        cleanup:
        if(error1)
        {
            WSACleanup();
        }
        if(error2)
        {
            WSACleanup();
            closesocket(server1);
        }
        if(error3)
        {
            WSACleanup();
            closesocket(server1);
            CloseHandle(fhand);
        }
        return 0;
    }
    Last edited by c0ldshadow; November 22nd, 2006 at 08:26 AM.

  4. #4
    Join Date
    Sep 2004
    Location
    this
    Posts
    115

    Re: Download a file using http & winsock

    here is the finished program. if anyone sees a flaw in the code, please let me know.

    everything appears to be working perfectly though. thanks for the help guys.

    an example usage would be:

    httpget someserver.com /somedir/blah.zip c:\savehere.zip


    here is the code, note that you need to link to wsa2_32.a

    Code:
    #include <string>
    #include <stdio.h>
    #include <winsock2.h>
    #define BUFFER_LEN (4096)
    using std::string;
    int main(int argc, char **argv)
    {
        HANDLE fhand;
        string request;
        int sendret;
        int iRecv;
        int iResponseLength=0;
        int offset;
        DWORD dw;
        string res2;
        char recvBuffer[BUFFER_LEN]={0};
        string response;
        const char lb[]="\r\n\r\n";
        const char http[]="http\x3a//";
        const char snsn[]="%s\n";
        bool error1=false;
        bool error2=false;
        bool error3=false;
        int len3=strlen(argv[3]);
        printf(snsn,"\n-=[  httpget v1.0 by Avery Tarasov");
        printf(snsn,"-=[  Email: c0ldshadow@deeptide.com");
        printf(snsn,"-=[  Web: www.DeepTide.com");
        printf(snsn,"-=[  Dedicated to my fiance, Ostine!\n");
        printf(snsn,"Example usage: httpget theserver.com /somefolder/somefile.zip C:\\savehere.zip");
        if(argc!=4)
        {
            printf(snsn,"\nInvalid usage");
            goto cleanup;
        }
        WSADATA wsaData;
        if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
        {
            printf(snsn,"\nError initializing Winsock 2.2");
            goto cleanup;
        }
        error1=true;
        if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
        {
            printf(snsn,"\nWinsock 2.2 not available");
            goto cleanup;
        }
        printf(snsn,"\nWinsock 2.2 initialized via wsa2_32.dll");
        struct hostent *h;
        struct sockaddr_in sa;
        SOCKET server1;
        h=gethostbyname(argv[1]);
        if(h==0)
        {
            printf(snsn,"\ngethostbyname() failed");
            goto cleanup;
        }
        printf("%s","\nHost lookup succeeded for ");
        printf(snsn,argv[1]);
        memcpy((char *)&sa.sin_addr,(char *)h->h_addr,sizeof(sa.sin_addr));
        sa.sin_family=h->h_addrtype;
        sa.sin_port=htons(80);
        server1=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(server1==INVALID_SOCKET)
        {
            printf(snsn,"\nsocket() failed");
            goto cleanup;
        }
        printf("%s","\nSocket initialized with handle ");
        printf("%d\n",server1);
        error1=false;
        error2=true;
        if(connect(server1,(struct sockaddr *)&sa,sizeof(sa))<0)
        {
            printf(snsn,"\nconnect() failed");
            goto cleanup;
        }
        printf("%s","\nNow connected to ");
        printf("%s",argv[1]);
        printf(snsn," via port 80");
        request+="GET http://";
        request+=argv[1];
        request+=argv[2];
        request+=" HTTP/1.0";
        request+=&lb[2];
        request+="Host: ";
        request+=argv[1];
        request+=lb;
        printf(snsn,"\nHTTP request constructed successfully:\n");
        printf(snsn,request.c_str());
        sendret=send(server1,request.c_str(),request.length(),0);
        if(sendret==-1)
        {
            printf(snsn,"send() failed");
            goto cleanup;
        }
        printf(snsn,"Successfully sent the HTTP request to the server");
    	fhand=CreateFile(argv[3],GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    	if(fhand==INVALID_HANDLE_VALUE)
    	{
            printf(snsn,"\nCreateFile() failed");
            goto cleanup;
    	}
        printf("%s","\nOpened file ");
        printf("%s",argv[3]);
        printf("%s"," with file handle ");
        printf("%d\n",fhand);
        error2=false;
        error3=true;
        printf(snsn,"\nPausing for 10 seconds before starting to receive data");
        Sleep(10000);
        while((iRecv=recv(server1,recvBuffer,BUFFER_LEN-1,0))>0)
        {
            char hex[5];
            string packet;
            packet.reserve(5*iRecv);
            printf(snsn,"\n");
            printf("%s","Receiving ");
            printf("%d",iRecv);
            printf(snsn," byte packet:\n");
            for(int i=0;i<iRecv;++i)
            {
                wsprintf(hex,"%02x",(unsigned char)recvBuffer[i]);
                packet.append(hex);
                printf("%s ",hex);
            }
            response.append(recvBuffer,iRecv);
            iResponseLength+=iRecv;
            ZeroMemory(recvBuffer,BUFFER_LEN);
        }
        if(iRecv==SOCKET_ERROR)
        {
            printf(snsn,"\n\nrecv() failed");
        }
        offset=response.find(lb)+4;
        printf("%s","\n\nDouble line breaks detected at file offset ");
        printf("%d\n",offset);
        if(offset!=string::npos)
        {
            res2.assign(response,offset,response.size());
            if(WriteFile(fhand,res2.data(),res2.size(),&dw,0)==0)
            {
                printf(snsn,"\nWriteFile() failed");
                goto cleanup;
            }
            else
            {
                printf("%s","\nFile successfully downloaded and saved to ");
                printf(snsn,argv[3]);
            }
        }
        cleanup:
        if(error1)
        {
            WSACleanup();
        }
        if(error2)
        {
            WSACleanup();
            closesocket(server1);
        }
        if(error3)
        {
            WSACleanup();
            closesocket(server1);
            CloseHandle(fhand);
        }
        return 0;
    }

  5. #5
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: Download a file using http & winsock

    Delete the call to Sleep(). There is no reason for, and your selection of 10 seconds is completely arbitrary anyway. The call to recv() will automatically block for however long it takes the server to respond.

    I think the HTTP request should omit the server name. In your code, if you are trying to get /somedir/blah.zip from someserver.com, you are connecting to someserver.com and sending:
    Code:
    GET http://someserver.com/somedir/blah.zip HTTP/1.0 <CRLF>
    Host: someserver.com <CRLF>
    <CRLF>
    Note to others reading this post: It should be obvious that you do not actually send the string <CRLF>. What's actually sent is a carriage return character, followed by a line feed character.

    It's my understanding, however, that under section 5.1.2 of rfc 1945 (which defines the HTTP/1.0 protocol), the above format is only allowed when making a request through a proxy. When making a request directly to a server, then under HTTP/1.0, there's no need to send the server's name in the request. In addition, the "Host" header is not be supported under HTTP/1.0 and probably would be ignored. So, your request (after connecting to the server, should be a single line like this:
    Code:
    GET /somedir/blah.zip HTTP/1.0 <CRLF>
    <CRLF>
    For a copy of rfc 1945, try ftp://ftp.rfc-editor.org/in-notes/rfc1945.txt . Section 5.1.2 is copied below:
    Quote Originally Posted by rfc 1945
    5.1.2 Request-URI

    The Request-URI is a Uniform Resource Identifier (Section 3.2) and
    identifies the resource upon which to apply the request.

    Request-URI = absoluteURI | abs_path

    The two options for Request-URI are dependent on the nature of the
    request.

    The absoluteURI form is only allowed when the request is being made
    to a proxy. The proxy is requested to forward the request and return
    the response. If the request is GET or HEAD and a prior response is
    cached, the proxy may use the cached message if it passes any
    restrictions in the Expires header field. Note that the proxy may
    forward the request on to another proxy or directly to the server
    specified by the absoluteURI. In order to avoid request loops, a
    proxy must be able to recognize all of its server names, including
    any aliases, local variations, and the numeric IP address. An example
    Request-Line would be:

    GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.0

    The most common form of Request-URI is that used to identify a
    resource on an origin server or gateway. In this case, only the
    absolute path of the URI is transmitted (see Section 3.2.1,
    abs_path). For example, a client wishing to retrieve the resource
    above directly from the origin server would create a TCP connection
    to port 80 of the host "www.w3.org" and send the line:

    GET /pub/WWW/TheProject.html HTTP/1.0

    followed by the remainder of the Full-Request. Note that the absolute
    path cannot be empty; if none is present in the original URI, it must
    be given as "/" (the server root).

    The Request-URI is transmitted as an encoded string, where some
    characters may be escaped using the "% HEX HEX" encoding defined by
    RFC 1738 [4]. The origin server must decode the Request-URI in order
    to properly interpret the request.
    Mike

  6. #6
    Join Date
    Sep 2004
    Location
    this
    Posts
    115

    Re: Download a file using http & winsock

    does this look better now?

    thanks for all the help mike!

    Code:
    #include <string>
    #include <stdio.h>
    #include <winsock2.h>
    #define BUFFER_LEN (4096)
    using std::string;
    int main(int argc, char **argv)
    {
        HANDLE fhand;
        string request;
        int sendret;
        int iRecv;
        int iResponseLength=0;
        int offset;
        DWORD dw;
        string res2;
        char recvBuffer[BUFFER_LEN]={0};
        string response;
        const char lb[]="\r\n\r\n";
        const char http[]="http\x3a//";
        const char snsn[]="%s\n";
        bool error1=false;
        bool error2=false;
        bool error3=false;
        int len3=strlen(argv[3]);
        printf(snsn,"\n-=[  httpget v1.0 by Avery Tarasov");
        printf(snsn,"-=[  Email: c0ldshadow@deeptide.com");
        printf(snsn,"-=[  Web: www.DeepTide.com");
        printf(snsn,"-=[  Dedicated to my fiance, Ostine!\n");
        printf(snsn,"Example usage: httpget theserver.com /somefolder/somefile.zip C:\\savehere.zip");
        if(argc!=4)
        {
            printf(snsn,"\nInvalid usage");
            goto cleanup;
        }
        WSADATA wsaData;
        if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
        {
            printf(snsn,"\nError initializing Winsock 2.2");
            goto cleanup;
        }
        error1=true;
        if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
        {
            printf(snsn,"\nWinsock 2.2 not available");
            goto cleanup;
        }
        printf(snsn,"\nWinsock 2.2 initialized via wsa2_32.dll");
        struct hostent *h;
        struct sockaddr_in sa;
        SOCKET server1;
        h=gethostbyname(argv[1]);
        if(h==0)
        {
            printf(snsn,"\ngethostbyname() failed");
            goto cleanup;
        }
        printf("%s","\nHost lookup succeeded for ");
        printf(snsn,argv[1]);
        memcpy((char *)&sa.sin_addr,(char *)h->h_addr,sizeof(sa.sin_addr));
        sa.sin_family=h->h_addrtype;
        sa.sin_port=htons(80);
        server1=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(server1==INVALID_SOCKET)
        {
            printf(snsn,"\nsocket() failed");
            goto cleanup;
        }
        printf("%s","\nSocket initialized with handle ");
        printf("%d\n",server1);
        error1=false;
        error2=true;
        if(connect(server1,(struct sockaddr *)&sa,sizeof(sa))<0)
        {
            printf(snsn,"\nconnect() failed");
            goto cleanup;
        }
        printf("%s","\nNow connected to ");
        printf("%s",argv[1]);
        printf(snsn," via port 80");
        request+="GET http://";
        request+=argv[1];
        request+=argv[2];
        request+=" HTTP/1.0";
        request+=lb;
        printf(snsn,"\nHTTP request constructed successfully:\n");
        printf(snsn,request.c_str());
        sendret=send(server1,request.c_str(),request.length(),0);
        if(sendret==-1)
        {
            printf(snsn,"send() failed");
            goto cleanup;
        }
        printf(snsn,"Successfully sent the HTTP request to the server");
    	fhand=CreateFile(argv[3],GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    	if(fhand==INVALID_HANDLE_VALUE)
    	{
            printf(snsn,"\nCreateFile() failed");
            goto cleanup;
    	}
        printf("%s","\nOpened file ");
        printf("%s",argv[3]);
        printf("%s"," with file handle ");
        printf("%d\n",fhand);
        error2=false;
        error3=true;
        while((iRecv=recv(server1,recvBuffer,BUFFER_LEN-1,0))>0)
        {
            char hex[5];
            string packet;
            packet.reserve(5*iRecv);
            printf(snsn,"\n");
            printf("%s","Receiving ");
            printf("%d",iRecv);
            printf(snsn," byte packet:\n");
            for(int i=0;i<iRecv;++i)
            {
                wsprintf(hex,"%02x",(unsigned char)recvBuffer[i]);
                packet.append(hex);
                printf("%s ",hex);
            }
            response.append(recvBuffer,iRecv);
            iResponseLength+=iRecv;
            ZeroMemory(recvBuffer,BUFFER_LEN);
        }
        if(iRecv==SOCKET_ERROR)
        {
            printf(snsn,"\n\nrecv() failed");
        }
        offset=response.find(lb)+4;
        printf("%s","\n\nDouble line breaks detected at file offset ");
        printf("%d\n",offset);
        if(offset!=string::npos)
        {
            res2.assign(response,offset,response.size());
            if(WriteFile(fhand,res2.data(),res2.size(),&dw,0)==0)
            {
                printf(snsn,"\nWriteFile() failed");
                goto cleanup;
            }
            else
            {
                printf("%s","\nFile successfully downloaded and saved to ");
                printf(snsn,argv[3]);
            }
        }
        cleanup:
        if(error1)
        {
            WSACleanup();
        }
        if(error2)
        {
            WSACleanup();
            closesocket(server1);
        }
        if(error3)
        {
            WSACleanup();
            closesocket(server1);
            CloseHandle(fhand);
        }
        return 0;
    }

  7. #7
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: Download a file using http & winsock

    Not quite. You deleted the "Hosts:" header, but you're still sending an absolute URI instead of the path only. Try this:

    Code:
        // ... 
        printf("%s","\nNow connected to ");
        printf("%s",argv[1]);
        printf(snsn," via port 80");
        request+="GET ";  // delete the http:// part
        // delete this too: request+=argv[1];
        request+=argv[2];
        request+=" HTTP/1.0";
        request+=lb;
        printf(snsn,"\nHTTP request constructed successfully:\n");
        // ..
    Mike

  8. #8
    Join Date
    Sep 2004
    Location
    this
    Posts
    115

    Re: Download a file using http & winsock

    hey

    i tried changing the code to:

    Code:
        printf("%s","\nNow connected to ");
        printf("%s",argv[1]);
        printf(snsn," via port 80");
        request+="GET ";
        //request+=argv[1];
        request+=argv[2];
        request+=" HTTP/1.0";
        request+=lb;
    but now the program woln't work when i do:

    httpget deeptide.com /pubzip/fsum.zip c:\asd.zip

    in the file some of the data says:
    the url /pubzip/fsum.zip was not found on the server

    with my old code, the program worked though

  9. #9
    Join Date
    Sep 2004
    Location
    this
    Posts
    115

    Re: Download a file using http & winsock

    is it because the server is http 1.1?

    Code:
    Response from server:
    
    HTTP/1.1 200 OK
    Date: Sat, 25 Nov 2006 13:17:17 GMT
    Server: Apache/1.3.37 (Unix) mod_gzip/1.3.26.1a mod_auth_passthrough/1.8 mod_log
    _bytes/1.2 mod_bwlimited/1.4 PHP/4.3.11 FrontPage/5.0.2.2635.SR1.2 mod_ssl/2.8.2
    8 OpenSSL/0.9.7a
    Last-Modified: Sat, 24 Sep 2005 17:58:17 GMT
    ETag: "4e0367-13fd1-433593b9"
    Accept-Ranges: bytes
    Content-Length: 81873
    Connection: close
    Content-Type: application/zip

  10. #10
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: Download a file using http & winsock

    Yes, you're correct: It's because it's an HTTP/1.1 server.

    You must include the "Host:" header, to allow an HTTP/1.1 server to find the resource. An HTTP/1.0 server will ignore it. Sorry to have given you inaccurate advice. You learn something new every day.

    As background, under HTTP/1.1, a client must, at a minimum:

    1. include the Host: header with each request
    2. accept responses with chunked data
    3. either support persistent connections, or include the "Connection: close" header with each request
    4. handle the "100 Continue" response

    The last three can be difficult to program, which is why I suggested that you use HTTP/1.0 instead.

    However, when an HTTP/1.1 server receives an HTTP/1.0 request, it might not know how to find the resource. HTTP/1.1 servers are multi-homed, meaning that the the address www.server1.com and www.server2.com might point to the exact same IP address. That's why HTTP/1.1 requires the "Host:" header.

    Here is the pertinent portion of the HTTP/1.1 spec that details the action of an HTTP/1.1 server that receives an HTTP/1.0 request (from ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt ). The last paragraph is the important one:
    Quote Originally Posted by rfc 2616 section 5.2
    5.2 The Resource Identified by a Request

    The exact resource identified by an Internet request is determined by
    examining both the Request-URI and the Host header field.

    An origin server that does not allow resources to differ by the
    requested host MAY ignore the Host header field value when
    determining the resource identified by an HTTP/1.1 request. (But see
    section 19.6.1.1 for other requirements on Host support in HTTP/1.1.)

    An origin server that does differentiate resources based on the host
    requested (sometimes referred to as virtual hosts or vanity host
    names) MUST use the following rules for determining the requested
    resource on an HTTP/1.1 request:

    1. If Request-URI is an absoluteURI, the host is part of the
    Request-URI. Any Host header field value in the request MUST be
    ignored.

    2. If the Request-URI is not an absoluteURI, and the request includes
    a Host header field, the host is determined by the Host header
    field value.

    3. If the host as determined by rule 1 or 2 is not a valid host on
    the server, the response MUST be a 400 (Bad Request) error message.

    Recipients of an HTTP/1.0 request that lacks a Host header field MAY
    attempt to use heuristics (e.g., examination of the URI path for
    something unique to a particular host) in order to determine what
    exact resource is being requested.
    Note the very last part, which explains what an HTTP/1.1 server should do when confronted with a Host-less request.

    Here, for your program, when you modified the request down to a single line of
    Code:
    GET /path/filemane HTTP/1.0 <CRLF>
    <CRLF>
    the HTTP/1.1 server had no way of telling which host it should get the resource from. So it returned "404 Not Found".

    Under the bolded section of 5.2 (above), when you included the full URI in the request:
    Code:
    GET http://server/path/filemane HTTP/1.0 <CRLF>
    <CRLF>
    then the HTTP/1.1 server could apply "heurisitcs" to find the resource you were asking for. However, this format of request might be non-compliant with HTTP/1.0, which states that the full URI should only be used with a proxy. The solution is to include the "Host:" header, which HTTP/1.0 servers will ignore, and which will allow HTTP/1.1 servers to disambiguate the resource:
    Code:
    GET /path/filemane HTTP/1.0 <CRLF>
    Host: server <CRLF>
    <CRLF>
    So, you code should look like this:
    Code:
    // ....
    printf("%s","\nNow connected to ");
    printf("%s",argv[1]);
    printf(snsn," via port 80");
    request+="GET ";  // not needed // http://";
    // not needed // request+=argv[1];
    request+=argv[2];
    request+=" HTTP/1.0";
    request+=&lb[2];
    request+="Host: ";  // "Host:" is necessary
    request+=argv[1];
    request+=lb;
    printf(snsn,"\nHTTP request constructed successfully:\n");
    
    // ....
    I have tested this code and it works.

    Incidentally, for a very approachable tutorial on writing code for HTTP clients and servers, I recommend "HTTP Made Really Easy: A Practical Guide to Writing Clients and Servers" by James Marshall at http://www.jmarshall.com/easy/http/

    Mike
    Last edited by MikeAThon; November 25th, 2006 at 01:19 PM.

  11. #11
    Join Date
    Sep 2004
    Location
    this
    Posts
    115

    Re: Download a file using http & winsock

    thanks for your continued support, MikeAThon. do you have a website? if so i can link back to you if you want. thanks for your help again. im going to read up on that http server webpage

    here is the working & updated code.

    Code:
    #include <string>
    #include <stdio.h>
    #include <winsock2.h>
    #define BUFFER_LEN (4096)
    using std::string;
    int main(int argc, char **argv)
    {
        HANDLE fhand;
        string request;
        int sendret;
        int iRecv;
        int iResponseLength=0;
        int offset;
        DWORD dw;
        string res2;
        char recvBuffer[BUFFER_LEN]={0};
        string response;
        const char lb[]="\r\n\r\n";
        const char http[]="http\x3a//";
        const char snsn[]="%s\n";
        bool error1=false;
        bool error2=false;
        bool error3=false;
        int len3=strlen(argv[3]);
        printf(snsn,"\n-=[  httpget v1.0 by Avery Tarasov");
        printf(snsn,"-=[  Email: c0ldshadow@deeptide.com");
        printf(snsn,"-=[  Web: www.DeepTide.com");
        printf(snsn,"-=[  Dedicated to my fiance, Ostine!\n");
        printf(snsn,"Example usage: httpget theserver.com /somefolder/somefile.zip C:\\savehere.zip");
        if(argc!=4)
        {
            printf(snsn,"\nInvalid usage");
            goto cleanup;
        }
        WSADATA wsaData;
        if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
        {
            printf(snsn,"\nError initializing Winsock 2.2");
            goto cleanup;
        }
        error1=true;
        if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
        {
            printf(snsn,"\nWinsock 2.2 not available");
            goto cleanup;
        }
        printf(snsn,"\nWinsock 2.2 initialized via wsa2_32.dll");
        struct hostent *h;
        struct sockaddr_in sa;
        SOCKET server1;
        h=gethostbyname(argv[1]);
        if(h==0)
        {
            printf(snsn,"\ngethostbyname() failed");
            goto cleanup;
        }
        printf("%s","\nHost lookup succeeded for ");
        printf(snsn,argv[1]);
        memcpy((char *)&sa.sin_addr,(char *)h->h_addr,sizeof(sa.sin_addr));
        sa.sin_family=h->h_addrtype;
        sa.sin_port=htons(80);
        server1=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        if(server1==INVALID_SOCKET)
        {
            printf(snsn,"\nsocket() failed");
            goto cleanup;
        }
        error1=false;
        error2=true;
        if(connect(server1,(struct sockaddr *)&sa,sizeof(sa))<0)
        {
            printf(snsn,"\nconnect() failed");
            goto cleanup;
        }
        printf("%s","\nNow connected to ");
        printf("%s",argv[1]);
        printf(snsn," via port 80");
        request+="GET ";
        request+=argv[2];
        request+=" HTTP/1.0";
        request+=&lb[2];
        request+="Host: ";
        request+=argv[1];
        request+=lb;
        printf(snsn,"\nHTTP request constructed successfully:\n");
        printf(snsn,request.c_str());
        sendret=send(server1,request.c_str(),request.length(),0);
        if(sendret==-1)
        {
            printf(snsn,"send() failed");
            goto cleanup;
        }
        printf(snsn,"Successfully sent HTTP request to the server");
        printf(snsn,"\nWaiting for download to complete");
    	fhand=CreateFile(argv[3],GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
    	if(fhand==INVALID_HANDLE_VALUE)
    	{
            printf(snsn,"\nCreateFile() failed");
            goto cleanup;
    	}
        error2=false;
        error3=true;
        while((iRecv=recv(server1,recvBuffer,BUFFER_LEN-1,0))>0)
        {
            /*
            char hex[5];
            string packet;
            packet.reserve(5*iRecv);
            printf(snsn,"\n");
            printf("%s","Receiving ");
            printf("%d",iRecv);
            printf(snsn," byte packet:\n");
            for(int i=0;i<iRecv;++i)
            {
                wsprintf(hex,"%02x",(unsigned char)recvBuffer[i]);
                packet.append(hex);
                printf("%s ",hex);
            }
            */
            response.append(recvBuffer,iRecv);
            iResponseLength+=iRecv;
            ZeroMemory(recvBuffer,BUFFER_LEN);
        }
        if(iRecv==SOCKET_ERROR)
        {
            printf(snsn,"\n\nrecv() failed");
        }
        offset=response.find(lb)+4;
        if(offset!=string::npos)
        {
            printf("%s","\n\nFile starts at offset ");
            printf("%d\n",offset);
            printf(snsn,"\nInitial response from server:\n");
            for(int j=0;j<offset;++j)
            {
                printf("%c",response[j]);
            }
            res2.assign(response,offset,response.size());
            if(WriteFile(fhand,res2.data(),res2.size(),&dw,0)==0)
            {
                printf(snsn,"\nWriteFile() failed");
                goto cleanup;
            }
            else
            {
                printf("%s","\nFile successfully downloaded and saved to ");
                printf(snsn,argv[3]);
            }
        }
        cleanup:
        if(error1)
        {
            WSACleanup();
        }
        if(error2)
        {
            WSACleanup();
            closesocket(server1);
        }
        if(error3)
        {
            WSACleanup();
            closesocket(server1);
            CloseHandle(fhand);
        }
        return 0;
    }

  12. #12
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,553

    Re: Download a file using http & winsock

    You're welcome! I'm glad it's working.

    I don't have a website, but thanks for the offer of linking.

    Mike

  13. #13
    Join Date
    Mar 2012
    Posts
    3

    sending file to http server via http request

    hi..i have to send file from client to http server via http request .
    i have make client and server program using winsock and it work fine for sending data from client to server but now i have to send text/xml file to server via http request.

  14. #14
    Join Date
    Mar 2012
    Posts
    3

    Re: Download a file using http & winsock

    hi ...
    i have to send file from client to http server via http request .
    i have make client and server program using winsock and it work fine for sending data from client to server but now i have to send text/xml file to server via http request. help

  15. #15
    Join Date
    Mar 2012
    Posts
    3

    Re: Download a file using http & winsock

    how server send the file to client through http request/response. what the server do for that .how it send the file to client with http request.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Azure Activities Information Page

Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center