/* * HTTP Connector * * Douglas Thrift * * HttpConnector.cpp */ #include #include #include #include #include #ifndef _WIN32 #include #include #include #include #include #include #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 typedef int SOCKET; #else #include #include #endif // _WIN32 using namespace std; string program; void error(const string prefix, bool host = false); void death(); string platform(); int main(int argc, char* argv[]) { SOCKET sock; struct sockaddr_in address; struct hostent* addressHost; struct servent* addressServ; string host = "localhost"; unsigned port = 80; string serv = "http"; string path = "/"; bool get = true; program = argv[0]; for (int index = 1; index < argc; index++) { string arg = argv[index]; switch (index) { case 1: host = arg; break; case 2: serv = arg; break; case 3: path = arg; break; default: get = (arg == "head") ? false : true; break; } } #ifdef _WIN32 WSADATA data; if (WSAStartup(MAKEWORD(2, 0) != 0, &data)) { error(program + ": WSAStartup()"); death(); } #endif if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { error(program + ": Socket"); death(); } address.sin_family = AF_INET; if ((addressHost = gethostbyname(host.c_str())) == NULL) { error(program + ": Host: " + host, true); death(); } address.sin_addr = *((in_addr*)*addressHost->h_addr_list); port = strtoul(serv.c_str(), 0, 0); if (port == 0) { if ((addressServ = getservbyname(serv.c_str(), "tcp")) == NULL) { error(program + ": Service: " + serv); death(); } address.sin_port = addressServ->s_port; port = ntohs(addressServ->s_port); } else { address.sin_port = htons(port); } if (connect(sock, (sockaddr*)&address, sizeof(sockaddr_in)) == SOCKET_ERROR) { error(program + ": Connect"); death(); } char* buffer = new char[BUFSIZ + 1]; if (get) { sprintf(buffer, "GET %s HTTP/1.1\r\n", path.c_str()); send(sock, buffer, strlen(buffer), 0); } else { sprintf(buffer, "HEAD %s HTTP/1.1\r\n", path.c_str()); send(sock, buffer, strlen(buffer), 0); } sprintf(buffer, "Accept: text/html; text/plain\r\n"); send(sock, buffer, strlen(buffer), 0); sprintf(buffer, "User-Agent: HttpConnector/1.1 (%s)\r\n", platform().c_str()); send(sock, buffer, strlen(buffer), 0); if (port == 80) { sprintf(buffer, "Host: %s\r\n", host.c_str()); send(sock, buffer, strlen(buffer), 0); } else { sprintf(buffer, "Host: %s:%u\r\n", host.c_str(), port); send(sock, buffer, strlen(buffer), 0); } sprintf(buffer, "Connection: close\r\n"); send(sock, buffer, strlen(buffer), 0); sprintf(buffer, "\r\n"); send(sock, buffer, strlen(buffer), 0); delete [] buffer; string line; int size = 1; while (size == 1) { char byte; do { size = recv(sock, &byte, 1, 0); if (byte != '\r' && byte != '\n') { line += byte; } } while (byte != '\n'); cout << line << (size == 1 ? "\n" : ""); line.erase(); } #ifdef _WIN32 closesocket(sock); WSACleanup(); #else close(sock); #endif return 0; } void error(const string prefix, bool host) { #ifdef _WIN32 string error; switch (WSAGetLastError()) { case WSAEACCES: error = "Permission denied."; break; case WSAEADDRINUSE: error = "Address already in use."; break; case WSAEADDRNOTAVAIL: error = "Cannot assign requested address."; break; case WSAEAFNOSUPPORT: error = "Address family not supported by protocol family."; break; case WSAEALREADY: error = "Operation already in progress."; break; case WSAECONNABORTED: error = "Software caused connection abort."; break; case WSAECONNREFUSED: error = "Connection refused."; break; case WSAECONNRESET: error = "Connection reset by peer."; break; case WSAEDESTADDRREQ: error = "Destination address required."; break; case WSAEFAULT: error = "Bad address."; break; case WSAEHOSTDOWN: error = "Host is down."; break; case WSAEHOSTUNREACH: error = "No route to host."; break; case WSAEINPROGRESS: error = "Operation now in progress."; break; case WSAEINTR: error = "Interrupted function call."; break; case WSAEINVAL: error = "Invalid argument."; break; case WSAEISCONN: error = "Socket is already connected."; break; case WSAEMFILE: error = "Too many open files."; break; case WSAEMSGSIZE: error = "Message too long."; break; case WSAENETDOWN: error = "Network is down."; break; case WSAENETRESET: error = "Network dropped connection on reset."; break; case WSAENETUNREACH: error = "Network is unreachable."; break; case WSAENOBUFS: error = "No buffer space available."; break; case WSAENOPROTOOPT: error = "Bad protocol option."; break; case WSAENOTCONN: error = "Socket is not connected."; break; case WSAENOTSOCK: error = "Socket operation on non-socket."; break; case WSAEOPNOTSUPP: error = "Operation not supported."; break; case WSAEPFNOSUPPORT: error = "Protocol family not supported."; break; case WSAEPROCLIM: error = "Too many processes."; break; case WSAEPROTONOSUPPORT: error = "Protocol not supported."; break; case WSAEPROTOTYPE: error = "Protocol wrong type for socket."; break; case WSAESHUTDOWN: error = "Cannot send after socket shutdown."; break; case WSAESOCKTNOSUPPORT: error = "Socket type not supported."; break; case WSAETIMEDOUT: error = "Connection timed out."; break; case WSATYPE_NOT_FOUND: error = "Class type not found."; break; case WSAEWOULDBLOCK: error = "Resource temporarily unavailable."; break; case WSAHOST_NOT_FOUND: error = "Host not found."; break; case WSA_INVALID_HANDLE: error = "Specified event object handle is invalid."; break; case WSA_INVALID_PARAMETER: error = "One or more parameters are invalid."; break; // case WSAINVALIDPROCTABLE: // error = "Invalid procedure table from service provider."; // break; // case WSAINVALIDPROVIDER: // error = "Invalid service provider version number."; // break; case WSA_IO_INCOMPLETE: error = "Overlapped I/O event object not in signaled state."; break; case WSA_IO_PENDING: error = "Overlapped operations will complete later."; break; case WSA_NOT_ENOUGH_MEMORY: error = "Insufficient memory available."; break; case WSANOTINITIALISED: error = "Successful WSAStartup not yet performed."; break; case WSANO_DATA: error = "Valid name, no data record of requested type."; break; case WSANO_RECOVERY: error = "This is a non-recoverable error."; break; // case WSAPROVIDERFAILEDINIT: // error = "Unable to initialize a service provider."; // break; case WSASYSCALLFAILURE: error = "System call failure."; break; case WSASYSNOTREADY: error = "Network subsystem is unavailable."; break; case WSATRY_AGAIN: error = "Non-authoritative host not found."; break; case WSAVERNOTSUPPORTED: error = "WINSOCK.DLL version out of range."; break; case WSAEDISCON: error = "Graceful shutdown in progress."; break; case WSA_OPERATION_ABORTED: error = "Overlapped operation aborted."; break; default: error = "Unknown error."; break; } cerr << prefix << ": " << error << "\n"; #else if (host) { herror(prefix.c_str()); } else { perror(prefix.c_str()); } #endif } void death() { #ifdef _WIN32 WSACleanup(); #endif exit(1); } string platform() { string os; string version; string architecture; string marketing; #ifdef _WIN32 OSVERSIONINFO* computer = new OSVERSIONINFO; computer->dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(computer); os = computer->dwPlatformId == VER_PLATFORM_WIN32_NT ? "Windows NT" : "Windows"; unsigned major = computer->dwMajorVersion; unsigned minor = computer->dwMinorVersion; delete computer; SYSTEM_INFO* system = new SYSTEM_INFO; GetSystemInfo(system); switch (system->wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: architecture = "ix86"; break; case PROCESSOR_ARCHITECTURE_MIPS: architecture = "mips"; break; case PROCESSOR_ARCHITECTURE_ALPHA: architecture = "alpha"; break; case PROCESSOR_ARCHITECTURE_PPC: architecture = "ppc"; break; case PROCESSOR_ARCHITECTURE_IA64: architecture = "ia64"; break; case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: architecture = "ix86_on_win64"; break; case PROCESSOR_ARCHITECTURE_AMD64: architecture = "amd64"; break; default: architecture = "unknown"; break; } char* cversion = new char[1024]; sprintf(cversion, "%u.%u", major, minor); version = cversion; delete [] cversion; if (major == 4 && minor <= 3 && os != "Windows NT") { marketing = " [Windows 95]"; } else if (major == 4 && minor == 10 && os != "Windows NT") { marketing = " [Windows 98]"; } else if (major == 5 && minor == 0 && os == "Windows NT") { marketing = " [Windows 2000]"; } else if (major == 4 && minor == 90 && os != "Windows NT") { marketing = " [Windows ME]"; } else if (major == 5 && minor == 1 && os == "Windows NT") { marketing = " [Windows XP]"; } else if (major == 5 && minor == 2 && os == "Windows NT") { marketing = " [Windows .NET Server]"; } #else // _WIN32 struct utsname* computer = new struct utsname; uname(computer); os = computer->sysname; version = computer->release; architecture = computer->machine; delete computer; #endif // _WIN32 return os + " " + version + marketing + " " + architecture; }