-
November 21st, 2006, 02:08 PM
#1
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;
}
-
November 21st, 2006, 05:27 PM
#2
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 08:20 PM.
Reason: to change "+=" to "append"
-
November 21st, 2006, 11:46 PM
#3
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 09:26 AM.
-
November 23rd, 2006, 11:48 AM
#4
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;
}
-
November 23rd, 2006, 02:28 PM
#5
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:
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
-
November 23rd, 2006, 06:20 PM
#6
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;
}
-
November 24th, 2006, 01:19 PM
#7
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
-
November 25th, 2006, 08:04 AM
#8
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
-
November 25th, 2006, 08:18 AM
#9
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
-
November 25th, 2006, 02:12 PM
#10
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:
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 02:19 PM.
-
November 25th, 2006, 08:15 PM
#11
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;
}
-
November 27th, 2006, 05:52 PM
#12
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
-
March 7th, 2012, 01:15 AM
#13
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.
-
March 7th, 2012, 01:16 AM
#14
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
-
March 7th, 2012, 01:19 AM
#15
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|