/***SDOC******************************************************************************************* * * UbiSoft Development Network * --------------------------- * * FILE........: httpconfig.cpp * CREATION....: 11 Dec. 2001 * AUTHOR......: Guillaume Plante * * DESCRIPTION.: implementation of the CGSHttpConfig class * ************************************************************************************************** * FILE HISTORY ************************************************************************************************** * * DATE........: * AUTHOR......: * DESCRIPTION.: * ******************************************************************************************EDOC***/ #include "httpconfig.h" //these 2 are included for the binary mode in case of binary download #include #include #include //=================================================================================================== // CLASS CGSHttpConfig // METHOD CGSHttpConfig // AUTHOR: Guillaume Plante // CREATION: April 4, 2002 // // DESCRIPTION: Default constructor //=================================================================================================== CGSHttpConfig::CGSHttpConfig() { m_iTimeOut = 0; m_bInitialised = false; } //=================================================================================================== // CLASS CGSHttpConfig // METHOD PrintError // AUTHOR: Guillaume Plante // CREATION: April 4, 2002 // // DESCRIPTION: Print error code on stderr //=================================================================================================== void CGSHttpConfig::PrintError(const char * szError) { fprintf(stderr,"\nerror: %s\nwsalasterror: %d\n", szError, WSAGetLastError()); } //=================================================================================================== // CLASS CGSHttpConfig // METHOD Initialize // AUTHOR: Guillaume Plante // CREATION: April 4, 2002 // // DESCRIPTION: Initialize the class (winsock2) //=================================================================================================== bool CGSHttpConfig::Initialize() { if(m_bInitialised) return false; // set the default time out value m_iTimeOut = _DEFAULT_TIMEOUT; m_bInitialised = true; return true; } //=================================================================================================== // CLASS CGSHttpConfig // METHOD Uninitialize // AUTHOR: Guillaume Plante // CREATION: April 4, 2002 // // DESCRIPTION: Uninitialize the class (winsock2) //=================================================================================================== bool CGSHttpConfig::Uninitialize() { if(!m_bInitialised) return false; m_bInitialised = false; return true; } //=================================================================================================== // CLASS CGSHttpConfig // METHOD GetWebFile // AUTHOR: Guillaume Plante // CREATION: April 4, 2002 // // DESCRIPTION: Get the a file given a url and write it to a location //=================================================================================================== int CGSHttpConfig::GetWebFile(const char * szURL,const char * szLocalFileName) { _urlinfo UrlInfo; if(!ParseURL(szURL,&UrlInfo)) return -1; // Lookup host LPHOSTENT lpHostEntry; lpHostEntry = gethostbyname(UrlInfo.szHost); if (lpHostEntry == NULL) { PrintError("gethostbyname()"); return -1; } // file object FILE *fData = NULL; // make sure the file is empty first if(szLocalFileName) { // write to file if(!(fData = fopen(szLocalFileName,"w"))) { PrintError("Could not open local file"); return -1; } // set the output as binary in case of a jpg or else _setmode(_fileno(fData), _O_BINARY); fwrite("", 1, 1, fData); fclose(fData); } // Fill in the server address structure SOCKADDR_IN sa; sa.sin_family = AF_INET; sa.sin_addr = *((LPIN_ADDR)*lpHostEntry->h_addr_list); sa.sin_port = htons(UrlInfo.usPort); // Create a TCP/IP stream socket SOCKET Socket; Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (Socket == INVALID_SOCKET) { PrintError("socket()"); return -1; } // // Create an event object to be used with this socket // WSAEVENT hEvent; hEvent = WSACreateEvent(); if (hEvent == WSA_INVALID_EVENT) { PrintError("WSACreateEvent()"); closesocket(Socket); return -1; } // Make the socket non-blocking and // associate it with network event int nRet; nRet = WSAEventSelect(Socket, hEvent, FD_READ|FD_CONNECT|FD_CLOSE); if (nRet == SOCKET_ERROR) { PrintError("EventSelect()"); closesocket(Socket); WSACloseEvent(hEvent); return -1; } // Request a connection nRet = connect(Socket, (LPSOCKADDR)&sa, sizeof(SOCKADDR_IN)); if (nRet == SOCKET_ERROR) { nRet = WSAGetLastError(); if (nRet == WSAEWOULDBLOCK) { fprintf(stderr,"\nConnect would block"); } else { PrintError("connect()"); closesocket(Socket); WSACloseEvent(hEvent); return -1; } } // Handle async network events char szBuffer[4096]; WSANETWORKEVENTS events; while(1) { // Wait for something to happen //fprintf(stderr,"\nWaitForMultipleEvents()"); DWORD dwRet; dwRet = WSAWaitForMultipleEvents(1, &hEvent, FALSE, 1000, FALSE); if (dwRet == WSA_WAIT_TIMEOUT) { fprintf(stderr,"\nWait timed out"); break; } // Figure out what happened //fprintf(stderr,"\nWSAEnumNetworkEvents()"); nRet = WSAEnumNetworkEvents(Socket, hEvent,&events); if (nRet == SOCKET_ERROR) { PrintError("WSAEnumNetworkEvents()"); break; } // handling events // Connect event if (events.lNetworkEvents & FD_CONNECT) { // Send the http request // make the request MakeRequest(szBuffer,UrlInfo.szObject,UrlInfo.szHost); nRet = send(Socket, szBuffer, strlen(szBuffer), 0); if (nRet == SOCKET_ERROR) { PrintError("send()"); break; } } // Read event if (events.lNetworkEvents & FD_READ) { // Read the data and write it to stdout nRet = recv(Socket, szBuffer, sizeof(szBuffer), 0); if (nRet == SOCKET_ERROR) { PrintError("recv()"); break; } //fprintf(stderr,"\nRead %d bytes", nRet); if(szLocalFileName) { // write to file if(!(fData = fopen(szLocalFileName,"a+"))) { PrintError("Could not open local file"); return -1; } // set the output as binary in case of a jpg or else _setmode(_fileno(fData), _O_BINARY); fwrite(szBuffer, nRet, 1, fData); fclose(fData); } else { // set the output as binary in case of a jpg or else _setmode(_fileno(stdout), _O_BINARY); // Write to stdout fwrite(szBuffer, nRet, 1, stdout); } } // Close event if (events.lNetworkEvents & FD_CLOSE) break; } closesocket(Socket); WSACloseEvent(hEvent); return 1; } //=================================================================================================== // CLASS CGSHttpConfig // METHOD MakeRequest // AUTHOR: Guillaume Plante // CREATION: April 4, 2002 // // DESCRIPTION: Make a standard http "GET" request based on a absolute file path and hostname //=================================================================================================== char *CGSHttpConfig::MakeRequest(char * szBuffer,const char * szFile,const char * szHostname) { sprintf(szBuffer, "GET %s HTTP/1.1\nHost: %s\n\n", szFile,szHostname); return szBuffer; } //=================================================================================================== // CLASS CGSHttpConfig // METHOD ParseURL // AUTHOR: Guillaume Plante // CREATION: April 4, 2002 // // DESCRIPTION: Parse a URL to give back the server, object, service name and port number in a struct //=================================================================================================== bool CGSHttpConfig::ParseURL(const char *szURL,_urlinfo *UrlInfo) { char szTempURL[256]; char *pc = NULL; char *pcPort = NULL; char *pcObj = NULL; int cpt = 0; int len = 0; memset(UrlInfo->szHost,0,sizeof(UrlInfo->szHost)); memset(UrlInfo->szService,0,sizeof(UrlInfo->szService)); memset(UrlInfo->szObject,0,sizeof(UrlInfo->szObject)); UrlInfo->usPort = 0; // make a copy of the url strncpy(szTempURL,szURL,255); if(!strstr(szTempURL,HTTP_SEP_PROTO_HOST)) return false; // first find the service type pc = strtok(szTempURL,HTTP_SEP_PROTO_HOST); if(!pc) return false; // put service in uppercase len = strlen(pc); for(cpt = 0;cpt<=len;cpt++) { pc[cpt] = tolower(pc[cpt]); } // copy the service name strncpy(UrlInfo->szService,pc,sizeof(UrlInfo->szService)); // check for invalid service. if((strcmp(UrlInfo->szService,NET_SERVICE_HTTP))&&(strcmp(UrlInfo->szService,NET_SERVICE_FTP))&& (strcmp(UrlInfo->szService,NET_SERVICE_GOPHER))) return false; // make a copy of the url strncpy(szTempURL,szURL,255); // find the port is there is none, port is 80 (standard) pc = strchr(szTempURL,':'); if(pc) { if(pc = strtok(++pc,HTTP_SEP_SLASH)) pcPort = strrchr(pc,HTTP_SEP_COLON_INT); else return false; // could not determine hostname if(pcPort) { UrlInfo->usPort = atoi(++pcPort); if(pc = strtok(pc,HTTP_SEP_COLON)) strncpy(UrlInfo->szHost,pc,sizeof(UrlInfo->szHost)); else return false; // could not find hostname } else { strncpy(UrlInfo->szHost,pc,sizeof(UrlInfo->szHost)); UrlInfo->usPort = HTTP_DEFAULT_PORT; // well known http port } } else return false; // in case of badly formed url put the default http port if(!UrlInfo->usPort) UrlInfo->usPort = HTTP_DEFAULT_PORT; // make a copy of the url strncpy(szTempURL,szURL,255); // now find the object pcObj = strstr(szTempURL,UrlInfo->szHost); if(pcObj) { if(pcObj = strchr(pcObj+cpt,HTTP_SEP_SLASH_INT)) strncpy(UrlInfo->szObject,pcObj,sizeof(UrlInfo->szObject)); else strncpy(UrlInfo->szObject,"/",sizeof(UrlInfo->szObject)); } else return false; return true; }