Virtual Host Proxy Server
From time to time, I pick-up ideas from codeguru.com so I thought that I should contribute as well.
The program I'm submitting today is aimed at solving a problem that sounds simple but appears to be next to impossible: running multiple Web servers on a single Windows 95/98 machine. If you are running NT, you can assign multiple IP addresses to your networks card, edit the hosts file to translate domain names into IP addresses and assign multiple Websites to Internet Information Server...
It's a bit tricky but feasible. If you're running Windows 95 or 98, it's virtually impossible so I had to find a way around that.
What I've done is write a very simple proxy server that translate server names into a sub folder of your local machine so your can host as many Websites as you want with one single HTTP server.
Let's imagine your web root is C:\WebRoot\, you will put the files for http://www.a.com into C:\WebRoot\www.a.com\. The files for www.b.com will go in C:\WebRoot\www.b.com\ and so on.
What the proxy will actually do is replace http://www.a.com/index.htm by http://127.0.0.1/www.a.com/index.htm on the fly (127.0.0.1 is equivalent to localhost and is by definition the IP address of your local machine).
So to test the program, what you really need is a Web server, something as simple as Personal Web Server (PWS) from Microsoft and a browser (Netscape Navigator, Internet Explorer or anything else).
You have to create the directories for the virtual servers as mentioned above and you have to configure your browser to use a proxy.
Here is an example with Internet Explorer 5.0 from Microsoft (Tools>Internet Options>Connections>LAN Settings)
As you can see, by default the proxy is running on port 5060.
Something else you have to be aware of is that the proxy doesn't support HTTP 1.1. The way HTTP 1.1 handles connections is slightly more complicated than HTTP 1.0. To keep the code as simple as possible, I decided to support HTTP 1.0 only. Anyway it's the default behavior of the browser when you go through a proxy as you can see on the following screenshot of IE5.
The code is very basic and there are numerous ways to improve it but a) it solved my problem and b) it's short and easy to read. It also provides a very good example on how to use the CSocket classes which are very high level classes and not very well documented.
// VirtualHostProxy.cpp
// // Virtual Host Proxy Server
// (c) Franck JEANNIN 1999 - fjeannin@linkguard.com
// // Simulate multiple Web servers on one single Windows 95/98 machine
// // Does not support HTTP 1.1 (HTTP 1.0 only)
// Use high level MFC socket classes: CSocket
// #include "stdafx.h"
#include <afxsock.h> // MFC socket extensions
#include <conio.h>
#define BUFFERSIZE 10000
#define SERVERNAMEMAXSIZE 256
#define PROXYPORT 5060
#define SERVERADDRESS "127.0.0.1"
#define SERVERPORT 80
char Buffer[BUFFERSIZE+SERVERNAMEMAXSIZE];
int main(int argc, char* argv[])
{ CSocket Proxy;
CSocket Client;
CSocket Server;
// initialize MFC
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { printf("Fatal Error: MFC initialization failed\nPress any key\n"); getch(); return -1; } // initialize Socket support if (!AfxSocketInit()) { printf("Fatal Error: Socket initialization failed\nPress any key\n"); getch(); return -1; } // create Proxy socket if (!Proxy.Create(PROXYPORT)) { printf("Fatal Error: Proxy socket creation failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } if (!Proxy.Listen(1)) { printf("Fatal Error: Proxy socket activation failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } else { printf("Virtual Host Proxy Server started on port %d\n(c) Franck JEANNIN 1999\n\n",PROXYPORT); } while(1) { if (!Proxy.Accept(Client)) { printf("Fatal Error: Client connection to Proxy failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } int n = Client.Receive(Buffer,BUFFERSIZE); if (n == -1) { printf("Fatal Error: Client transmission to Proxy failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } Buffer[n] = 0; printf("Received from client: %s\n",Buffer); // calls to http://www.a.com/mypage.htm are transformed to calls to http://127.0.0.1/www.a.com/mypage.htm char* p = strstr(Buffer,"//"); if (p) { p += 2; memmove(p+sizeof(SERVERADDRESS),p,n); memcpy(p,SERVERADDRESS,sizeof(SERVERADDRESS)-1); *(p+sizeof(SERVERADDRESS)-1) = '/'; n += sizeof(SERVERADDRESS); } if (!Server.Create()) { printf("Fatal Error: Server socket creation failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } if (!Server.Connect(SERVERADDRESS,SERVERPORT)) { printf("Fatal Error: Server socket connection to HTTP server failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } n = Server.Send(Buffer,n); if (n == -1) { printf("Fatal Error: Proxy transmission to Server failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } Buffer[n] = 0; printf("Sent to server: %s\n",Buffer); while ( (n = Server.Receive(Buffer,BUFFERSIZE)) != 0) { if (n == -1) { printf("Fatal Error: Server transmission to Proxy failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } Buffer[n] = 0; printf("Received from server: %s\n",Buffer); n = Client.Send(Buffer,n); if (n == -1) { printf("Fatal Error: Proxy transmission to Server failed\nError %d\n\nPress any key\n",GetLastError()); getch(); return -1; } Buffer[n] = 0; printf("Sent to Client: %s\n",Buffer); } printf("Closing Client & Server sockets\n"); Client.Close(); Server.Close(); } return 0; }
History

Comments
Very good starting point
Posted by Legacy on 01/22/2004 12:00amOriginally posted by: Edgar Leon
Great and simple, I've succesfully modify it to meet my needs.
I'm very thankfull
Reply"www.163.com" cann't be logged on, use the proxy
Posted by Legacy on 10/25/2001 12:00amOriginally posted by: wisber
Your proxy don't work properly,
Replythe website "www.163.com" cann't be logged on.
Virtual Host Proxy Server
Posted by Legacy on 06/28/2001 12:00amOriginally posted by: George
Any ideas on how HTTP/1.1 persistant connections work?
ReplyI have done some experimentation and I am still mystified.
If I recv twice before sending something to the HTTP server I get a broken pipe, or error.
Anyway you have to add .
Posted by Legacy on 05/18/2001 12:00amOriginally posted by: michel
Very usefull for my first step in CSocket; Merci.
Insert a CWinApp instance at the beginning of your main().
Replyfor exemple CWinApp MyApp;
Have a look to the "help" for AfxWinInit and AfxSocketInit.
no response from client
Posted by Legacy on 04/20/2001 12:00amOriginally posted by: Adrian Austin
Hi,
Please Help. I found your code on the net. Good stuff. I'm currently trying to write a simple proxy server to sit in between our windows clients and the real proxy server. We're doing this so that we can do some clever authentication on client ip addresses.
Anyway, I found your code and thought this was the answer. I'd already tried a very similar thing in visual basic.
I still have a problem however,
in the command prompt window it all seems to work great. The http request comes in, is sent to the proxy server and the correct response comes back BUT, when I step throught the code I can see that it thinks it has successfully sent the response back to the client but Internet Explorer just sits there and eventually times out. I can't work out why this is happening.
Any ideas very much appretiated?
Also, will this work for ftp and all other protocols?
ReplyFor me either
Posted by Legacy on 03/13/2001 12:00amOriginally posted by: Chris
If I had a webpage with a graphic in it. The page would load the html page fine but would not continue loading graphics embedded in the page. It would stick on the while( n = server.receive(Buffer.BUFFERSIZE) ) != 0 ) line.
If I change the logic to check to see if the last receive was less then BUFFERSIZE it works under DEBUG mode only. I am not an expert at this so my debugging that error was futile.
ReplyYour proxy not work propery
Posted by Legacy on 01/16/2000 12:00amOriginally posted by: JP
Your proxy not work propery
Reply