GET_SOCK.C

/*++ 

Copyright 1996 - 1998 Microsoft Corporation

Module Name:

get_sock.c

Abstract:

This does a get using raw sockets

History:

09-Nov-1995 Created
15-Feb-1996 Added authentication support

--*/

#include <windows.h>
#include <winsock.h>

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "httpauth.h"

// globals

#define HD_AUTHENTICATE "WWW-Authenticate:"
#define HD_LENGTH "Content-Length:"
#define HD_CONNECTION "Connection:"

// list of Authentication methods to support

char achAuth[256];


// Helper functions

void SkipWhite(PSTR *ppS )
{
PSTR pS = *ppS;

while ( *pS && isspace(*pS) )
++pS;

*ppS = pS;
}


void SkipNonWhite(PSTR *ppS )
{
PSTR pS = *ppS;

while ( *pS && !isspace(*pS) )
++pS;

*ppS = pS;
}



BOOL
HttpGetSocket(
char * Verb,
char * Server,
char * URL,
BOOL DisplayHeaders,
DWORD ClientDataSize,
PSTR pchUserName,
PSTR pchPassword,
PSTR pszStore,
PSTR pszPref
)
/*++

Routine Description:

Issue a command to a HTTP server using authentication

Arguments:

Verb HTTP command : GET / HEAD / ...
Server server name
URL URL to send to the server
DisplayHeaders TRUE to display headers as received
ClientDataSize number of bytes to send in the request
pchUserName user name for authentication
pchPassword password for authentication
pszStore file name where to dump reply from server

Return Value:

Returns TRUE is successful; otherwise FALSE is returned.

--*/
{
char ReceiveBuffer[8*1024];
int Error;
BYTE Request[1024];
int RequestSize;
char * AcceptTypes[2] = {"*/*", NULL};
SOCKET Socket = INVALID_SOCKET;
WSADATA WsaData;
struct sockaddr_in Address;
struct hostent * HostEntry;
char Headers[] =
"HTTP/1.0\r\n"
"User-Agent: AuthClient\r\n"
"Accept: */*\r\n";
char CrLf[] = "\r\n";
BYTE ClientData[64*1024];
BOOL fKeepAlive = FALSE;
int cRec;
DWORD cLen;
BOOL fInHeader;
PSTR pchAuthData;
BOOL fServerKeepAlive = FALSE;
BOOL fNeedMoreData;
BOOL fNeedAuthenticate;
PSTR pH;
PSTR pN;
BOOL fStatusLine;
int Status = -1;
DWORD cToRead;
PSTR paAuth = achAuth;
BOOL fSt = FALSE;
int hnd = EOF;

Error = WSAStartup (0x101, &WsaData);

if (Error == SOCKET_ERROR)
{
fprintf(stderr, "Error in WSAStartup = %d\n", GetLastError());
return FALSE;
}

if ( !InitAuthorizationHeader() )
{
fprintf(stderr, "Cannot initialize security module\n" );
return FALSE;
}

memset( achAuth, '\0', sizeof(achAuth) );
pchAuthData = NULL;
fNeedAuthenticate = FALSE;

//
// Connect to the server
//

if ( pszStore != NULL )
if ( (hnd = _open( pszStore, _O_BINARY | _O_CREAT | _O_TRUNC | _O_RDWR, S_IREAD|S_IWRITE )) == EOF )
{
fprintf( stderr, "Can't create file %s\n", pszStore );
return FALSE;
}

again:

if ( Socket == INVALID_SOCKET )
{
Socket = socket(AF_INET, SOCK_STREAM, 0);

if (Socket == INVALID_SOCKET)
{
fprintf(stderr, "Error creating socket = %d\n", GetLastError());
fSt = FALSE;
goto ex;
}

Address.sin_family = AF_INET;
Address.sin_port = 0;
Address.sin_addr.s_addr = INADDR_ANY;

Error =
bind(
Socket,
(struct sockaddr *) &Address,
sizeof(Address));

if (Error)
{
fprintf(stderr, "Error in bind = %d\n", GetLastError());
fSt = FALSE;
goto ex;
}

Address.sin_family = AF_INET;
Address.sin_port = htons(80);
Address.sin_addr.s_addr = inet_addr(Server);

if (Address.sin_addr.s_addr == -1)
{
//
// Must be a server name
//
HostEntry = gethostbyname(Server);
if (HostEntry == NULL)
{
printf("unable to resolve %s\n", Server);
fSt = FALSE;
goto ex;
} else
{
Address.sin_addr.s_addr = *((unsigned long *) HostEntry->h_addr);
}
}

Error =
connect(
Socket,
(struct sockaddr *) &Address,
sizeof(Address));

if (Error)
{
fprintf(stderr, "Error connecting to %s = %d\n", Server, GetLastError());
fSt = FALSE;
goto ex;
}
}

//
// Send the client request
//

strcpy(Request, Verb);
strcat(Request, " ");
strcat(Request, URL);
strcat(Request, " ");
strcat(Request, Headers);
if (ClientDataSize)
{
sprintf(ClientData, "Content-Length: %d\r\n", ClientDataSize);
strcat(Request, ClientData);
}
if ( fKeepAlive )
{
strcat(Request, "Connection: Keep-Alive\r\n" );
}

if ( !AddAuthorizationHeader( Request + strlen(Request), achAuth, pchAuthData, pchUserName, pchPassword, &fNeedMoreData ) )
{
printf( "Authentication failed\n" );
fSt = FALSE;
goto ex;
}

strcat(Request, CrLf);

RequestSize = strlen(Request);

Error =
send(
Socket,
Request,
RequestSize,
0);

if (Error != RequestSize)
{
printf("Error in client send = %d, %d\n", Error, GetLastError());
fSt = FALSE;
goto ex;
}

if (ClientDataSize)
{
memset( ClientData, ' ', ClientDataSize );

//
// Send the client data
//

Error =
send(
Socket,
ClientData,
ClientDataSize,
0);

if ( (DWORD)Error != ClientDataSize)
{
printf("Error in client send = %d, %d\n", Error, GetLastError());
fSt = FALSE;
goto ex;
}
}

// parse status & header

cLen = (DWORD)-1;
fInHeader = TRUE;
fServerKeepAlive = FALSE;
fNeedAuthenticate = FALSE;

for ( pH = ReceiveBuffer, fStatusLine = TRUE ; fInHeader ; )
{
cRec = recv( Socket, pH, ReceiveBuffer+sizeof(ReceiveBuffer)-pH, 0 );
if ( cRec <= 0 )
{
closesocket( Socket );
Socket = INVALID_SOCKET;
break;
}
pH[ cRec ] = '\0';

// Iterate on header fields

while ( pN = strstr(pH, "\r\n" ) )
{
*pN = '\0';

if ( DisplayHeaders )
{
printf( "%s\n", pH );
}

if ( fStatusLine )
{
// This is the status line, decode status

SkipNonWhite( &pH );
SkipWhite( &pH );
Status = atoi( pH );
if ( Status == 401 )
{
fNeedAuthenticate = TRUE;
}
fStatusLine = FALSE;
}
else if ( pN == pH ) // end of header fields
{
if ( hnd != EOF )
write( hnd, pH+2, ReceiveBuffer+cRec-pH-2 );

cLen -= ( ReceiveBuffer+cRec-pH-2 );
fInHeader = FALSE;
break;
}
else if ( !strnicmp( pH, HD_AUTHENTICATE, sizeof(HD_AUTHENTICATE)-1 ) )
{
SkipNonWhite( &pH );
SkipWhite( &pH );

// check if we are already in the authentication sequence

if ( !IsInAuthorizationSequence() )
{
// append to list of supported authentication methods

strcpy( paAuth, pH );
paAuth += strlen( pH ) + 1;
}
else
{
// store pointer to authenticate blob

SkipNonWhite( &pH );
SkipWhite( &pH );
pchAuthData = pH;
}
}
else if ( !strnicmp( pH, HD_LENGTH, sizeof(HD_LENGTH)-1 ) )
{
// get content length

SkipNonWhite( &pH );
SkipWhite( &pH );
cLen = atoi( pH );
}
else if ( !strnicmp( pH, HD_CONNECTION, sizeof(HD_CONNECTION)-1 ) )
{
// check for keep-alive flag

SkipNonWhite( &pH );
SkipWhite( &pH );
if ( !strnicmp( pH, "Keep-Alive", sizeof("Keep-Alive")-1 ) )
fServerKeepAlive = TRUE;
}

pH = pN + 2;
}
}

// add final delimiter to list of supported authentication methods

if ( !IsInAuthorizationSequence() && fNeedAuthenticate )
{
*paAuth = '\0';

// Insure specified methods are supported localy

if ( !ValidateAuthenticationMethods( achAuth, pszPref ) )
{
// None of the server specified authentication methods
// are supported localy.

SetLastError( ERROR_ACCESS_DENIED );

fprintf( stderr, "No supported authentication method\n" );

fSt = FALSE;
goto ex;
}
}

// read message body

if ( Socket != INVALID_SOCKET )
{
for ( ; cLen ; )
{
if ( (cToRead = sizeof(ReceiveBuffer)) > cLen )
cToRead = cLen;
cRec = recv( Socket, ReceiveBuffer, cToRead, 0 );

if ( cRec <= 0 )
{
closesocket( Socket );
Socket = INVALID_SOCKET;
break;
}
if ( hnd != EOF )
write( hnd, ReceiveBuffer, cRec );

cLen -= cRec;
}
}

if ( !fServerKeepAlive )
{
if ( IsInAuthorizationSequence() )
{
fprintf( stderr, "Authentication rejected by server\n" );

fNeedAuthenticate = FALSE; // authentication failed
}

closesocket( Socket );
Socket = INVALID_SOCKET;
}

if ( fNeedAuthenticate )
{
fKeepAlive = TRUE;
goto again;
}

if ( Socket != INVALID_SOCKET )
closesocket(Socket);

fSt = Status == 200;

ex:
TerminateAuthorizationHeader();

if ( hnd != EOF )
close( hnd );

return fSt;
}