Very simple HTTP proxy

Just starting out? Need help? Post your questions and find answers here.
oliv
User
User
Posts: 42
Joined: Sun Aug 24, 2003 10:11 am
Location: France

Very simple HTTP proxy

Post by oliv »

Hi,
I'm trying to create a very simple HTTP proxy wich forward only 'GET' request and transmit the response, but my code has bug and I don't know how to fix it. Have you an idea or do you know a better way to make it ?

Thanks

(I can translate comments if it helps you)

Code: Select all

If InitNetwork() = 0
  MessageRequester("Erreur", "Initialisation du réseau impossible.")
  End
EndIf

;- **********     Declarations  ************************
; Constantes
#Max = 1
#T_Buffer_R_Nabaz = 2000

; Structures
Structure S_Serveur
  Event.l
  Port.l
EndStructure
Structure S_Client
  ID.l
  *Buffer.l
  Taille.l
  Commande.s
  Cookie.s
  Accept.s
  Host.s
  ContentType.s
  ContentLength.s
  Adresse.s
  Connexion.l
  Port.s
EndStructure


; Listes
NewList Clients.S_Client()


; Variables
Sortie.b
Define.l i, Length
Serveur.S_Serveur
Define.s Eol, Temp




;- **********     Initialisations    ****************

; Serveur 
Serveur\Port = 4444

; Autres
Eol = Chr(13) + Chr(10)




; Création du serveur
If CreateNetworkServer(0, Serveur\Port) = 0
  MessageRequester("Erreur", "Impossible de créer le serveur," + Eol + "le port '" + Str(Port) + "' est-il libre ?")
  End
EndIf






;-  **********     Fonctions      ******************
Procedure FillMemory(*Buffer,Taille.l,Car.l)
  For i.l = 0 To Taille - 1
    PokeL(*Buffer + i,Car)
  Next i
EndProcedure





If CreateFile(0,"Debug_Proxy.txt")



;- **********     Création de la fenêtre    *************
OpenWindow(0, 0, 0, 800, 600, "Nabaztag", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered)



CreateGadgetList(WindowID(0))



Repeat
  Select WindowEvent()
    Case #PB_Event_CloseWindow
      Sortie = 1
    Case #PB_Event_Gadget
      Select EventGadget()
      EndSelect
  EndSelect
      
      
  Serveur\Event = NetworkServerEvent()
  If Serveur\Event
    Select Serveur\Event
      Case #PB_NetworkEvent_Connect
        AddElement(Clients())
        Clients()\ID = EventClient()
        Clients()\Buffer = AllocateMemory(#T_Buffer_R_Nabaz)
        WriteStringN(0,"Nouveau client connecté, ClientID : " + Str(Clients()\ID))
          
      Case #PB_NetworkEvent_Disconnect
        WriteStringN(0,"Un client c'est déconnecté, ClientID : " + Str(EventClient()))
        ResetList(Clients())
        While NextElement(Clients())
          If Clients()\ID = EventClient()
            If Clients()\Connexion
              CloseNetworkConnection(Clients()\Connexion)
            EndIf
            FreeMemory(Clients()\Buffer)
            DeleteElement(Clients())
            Break
          EndIf
        Wend
          
      Case #PB_NetworkEvent_Data
        FillMemory(Clients()\Buffer, #T_Buffer_R_Nabaz, 0)
        ResetList(Clients())
        While NextElement(Clients())
          If Clients()\ID = EventClient()
              
            Clients()\Taille = ReceiveNetworkData(Clients()\ID, Clients()\Buffer, #T_Buffer_R_Nabaz)
            If PeekS(Clients()\Buffer,3) = "GET" ; Si on reçoit la commande 'GET'
                
              ; On détermine le header envoyé
              Clients()\Accept = ""
              Clients()\Host = ""
              Clients()\Cookie = ""
              Clients()\ContentType = ""
              Clients()\ContentLength = ""
              Clients()\Commande = StringField(PeekS(Clients()\Buffer,Clients()\Taille),1,Eol)
              For i = 1 To CountString(PeekS(Clients()\Buffer,Clients()\Taille),Eol) + 1
                Temp = StringField(PeekS(Clients()\Buffer,Clients()\Taille),i,Eol)
                If FindString(Temp,"Accept: ",1) : Clients()\Accept = Temp : EndIf
                If FindString(Temp,"Host: ",1) : Clients()\Host = Temp : EndIf
                If FindString(Temp,"Cookie: ",1) : Clients()\Cookie = Temp : EndIf
                If FindString(Temp,"Content-Type: ",1) : Clients()\ContentType = Temp :  EndIf
                If FindString(Temp,"Content-Length: ",1) : Clients()\ContentLength = Temp : EndIf
              Next i
              WriteStringN(0,"--- Commande reçue ---")
              WriteStringN(0,Clients()\Commande)
              WriteStringN(0,"Accept: [" + Clients()\Accept + "]")
              WriteStringN(0,"Host: [" + Clients()\Host + "]")
              WriteStringN(0,"Cookie: [" + Clients()\Cookie + "]")
              WriteStringN(0,"Content-Type: [" + Clients()\ContentType + "]")
              WriteStringN(0,"Content-Length: [" + Clients()\ContentLength + "]")
              WriteStringN(0,"---")
              
              
              
              ; On récupère le contenu du champ 'Host' pour s'y connecter
              Clients()\Adresse = Right(Clients()\Host, Len(Clients()\Host) - 6)
              Clients()\Port = StringField(Clients()\Adresse,2,":")
              If Clients()\Port = "" : Clients()\Port = "80" : EndIf
              Clients()\Adresse = StringField(Clients()\Adresse,1,":")
              Clients()\Adresse = RemoveString(Clients()\Adresse, " ")
              WriteStringN(0,"Adresse : " + Clients()\Adresse + " | Port : " + Clients()\Port)
              WriteStringN(0,"")
              Clients()\Connexion = OpenNetworkConnection(Clients()\Adresse,Val(Clients()\Port))
              
              
              ; Construction de la commande 'GET' à envoyer au serveur
              FillMemory(Clients()\Buffer, #T_Buffer_R_Nabaz, 0)
              
              Clients()\Commande = RemoveString(Clients()\Commande,":80")
              Debug Clients()\Commande
              
              
              Length = PokeS(Clients()\Buffer, Clients()\Commande + Eol)
              If Clients()\Host : Length + PokeS(Clients()\Buffer + Length, Clients()\Host + Eol) : EndIf
              Length + PokeS(Clients()\Buffer + Length, "User-Agent: ONabz-Proxy/1.0" + Eol)
              If Clients()\Cookie : Length + PokeS(Clients()\Buffer + Length, Clients()\Cookie + Eol) : EndIf
              If Clients()\Accept : Length + PokeS(Clients()\Buffer + Length, Clients()\Accept + Eol) : EndIf
              Length + PokeS(Clients()\Buffer + Length, "Connection: close" + Eol)
              WriteStringN(0,"--- Get construit ---")
              WriteStringN(0,PeekS(Clients()\Buffer))
              WriteStringN(0,"")
                
              
              ; On se connecte au serveur  
              If Clients()\Connexion 
                SendNetworkData(Clients()\Connexion, Clients()\Buffer, Length)
              Else
                WriteStringN(0,"Impossible de se connecter au serveur.")
                WriteStringN(0,"")
              EndIf
              
                
            Else
              Debug "Pas GET..."
            EndIf
            
            Break
          EndIf
        Wend

          
    EndSelect
  EndIf
    
  
  ResetList(Clients())
  While NextElement(Clients())
    If Clients()\Connexion
      If NetworkClientEvent(Clients()\Connexion)
        Repeat
          FillMemory(Clients()\Buffer, #T_Buffer_R_Nabaz, 0)
          Clients()\Taille = ReceiveNetworkData(Clients()\Connexion, Clients()\Buffer, #T_Buffer_R_Nabaz)
          tmp.l = SendNetworkData(Clients()\ID, Clients()\Buffer, Clients()\Taille)
          If tmp = -1 : Debug "---   Retour de -1  ---" : EndIf
          Delay(100)
        Until Clients()\Taille < #T_Buffer_R_Nabaz
        WriteStringN(0,"--- Données reçues ---")
        WriteStringN(0,Str(Clients()\Taille))
        WriteStringN(0,"")
      EndIf
    EndIf
  Wend
        
        
  
  Delay(10)
Until Sortie = 1

CloseFile(0)
Else
  Debug "Impossible d'ouvrir"
EndIf
End
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

is there a reason why you are processing all the header parts? you really only need the host and maybe port don't you? Everything else you should be able to just pass as is (unless you want to fiddle with it I guess).

I'm not at my home PC so I can't compile this but what does the input and output data look like from debug info on this proxy app?
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
oliv
User
User
Posts: 42
Joined: Sun Aug 24, 2003 10:11 am
Location: France

Post by oliv »

You are right, there is no reason to process all the header parts, it is not neaded. But I think the problem is not here but on the forwarding of the server response.
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

Your code was sending a "close"

Code: Select all

GET http://www.cnn.com/ HTTP/1.1
Host: www.cnn.com
User-Agent: ONabz-Proxy/1.0
Cookie: SelectedEdition=www; CNNid=Ga50a8350-19015-1185694590-181; s_pers=%20s_lastvisit%3D1197647984296%7C1292255984296%3B%20s_vnum%3D1200239984312%2526vn%253D1%7C1200239984312%3B%20s_invisit%3Dtrue%7C1197649784312%3B; s_vi=[CS]v1|46AC437E00002782-A140A1A00005EB1[CE]; lwp.weather=RJTI%7E398202858374
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Connection: close     < -- HERE !!!!!!!!!!!!!!!!!!!!!!!

If you change this to a "Connection: Keep-Alive" then it keeps going. (Untill it crashes due to the memory allocation method. ;) )

I'd get rid of that structure and pass what the client passes. Get that working cleanly first and then worry about fiddling with the passing data.
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
oliv
User
User
Posts: 42
Joined: Sun Aug 24, 2003 10:11 am
Location: France

Post by oliv »

Yes, I don't know why I send" close" and not "Keep-Alive"...
But it didn't change the problem....

But I can't understand what do you say :
I'd get rid of that structure and pass what the client passes. Get that working cleanly first and then worry about fiddling with the passing data.
Do you say that the header's treatment is wrong ?

You also speak about memory allocation : You're right, I could allocate memory witout the linked list.

Thanks


I just find a German code here, and he seems to have sames problems than me (my German level is so bad...), but he has the same method.

PB4.10 version of his code :

Code: Select all

;- Enumeration, Dim, NewList 
Enumeration;Gadgets 
 #cmdQuit 
EndEnumeration 

Enumeration;Fehler 
 #InitNetwork 
 #CreateNetworkServer 
EndEnumeration 

Structure Fehlerstruktur 
    Titel.s 
    Text.s 
EndStructure 

Global Dim Fehler.Fehlerstruktur(100) 

Structure ClientInformation 
 WebserverID.l 
 ClientID.l 
 Host.s 
EndStructure 

NewList ClientInfo.ClientInformation() 
NewList WebserverIDtoClientID.l() 


;- Variablen und Konstanten 

ControlledCancelb.b 
ToSendRequest.b 

*ReceiveBuffer = AllocateMemory(61440) 
*tmpstr = AllocateMemory(61440) 

laenge.l = 0 

Port = 4444 


Procedure InitFehler() 

 Fehler(InitNetwork)\Titel = "Netzwerk-Fehler" 
 Fehler(InitNetwork)\Text  = "Netzwerk konnte nicht initialisiert werden !" 

 Fehler(CreateNetworkServer)\Titel = "Proxy-Fehler" 
 Fehler(CreateNetworkServer)\Text  = "Proxy konnte nicht erstellt werden !" 

EndProcedure;InitFehler() 
  

Procedure Fehlermeldung(Nummer) 
 MessageRequester(Fehler(Nummer)\Titel, Fehler(Nummer)\Text, 0) 
EndProcedure;Fehlermeldung() 


Procedure cmdQuit_Click() 
;... 
End 
EndProcedure;cmdQuit_Click() 

Procedure InitFenster() 
  
 If OpenWindow(0,0,0,230,90,"Beispiel...",#PB_Window_SystemMenu|#PB_Window_ScreenCentered) 

  If CreateGadgetList(WindowID(0)) 
   ButtonGadget  (#cmdQuit, 10, 10,200, 20, "Good By !") 
  EndIf;CreateGadgetList 

  If CreateMenu(0, WindowID(0)) 
   MenuTitle("Menu") 
    MenuItem(1, "Eintrag 1") 
    MenuItem(2, "Eintrag 2") 
    MenuItem(3, "Eintrag 3") 
  EndIf;CreateMenu 

 Else;OpenWindow 
  End 
 EndIf;OpenWindow 

EndProcedure;InitFenster()  






Procedure.s CreateServerMessage(Title.s, Head.s, Text.s) 

 Message.s = "" 
 HTTPHeader.s = "" 
 Tag.s = "" 
 Monat.s = "" 

 ; Tag einstellen 
 Select DayOfWeek(Date()) 
  Case 0 
   Tag = ";Sun" 
  Case 1 
   Tag.s = ";Mon" 
  Case 2 
   Tag.s = ";Tue" 
  Case 3 
   Tag.s = ";Wed" 
  Case 4 
   Tag.s = ";Thu" 
  Case 5 
   Tag.s = ";Fri" 
  Case 6 
   Tag.s = ";Sat" 
 EndSelect 
  
 Select Month(Date()) 
  Case 1 
   MonthName.s = "Jan" 
  Case 2 
   MonthName.s = "Feb" 
  Case 3 
   MonthName.s = "Mrz" 
  Case 4 
   MonthName.s = "Apr" 
  Case 5 
   MonthName.s = "Mai" 
  Case 6 
   MonthName.s = "Jun" 
  Case 7 
   MonthName.s = "Jul" 
  Case 8 
   MonthName.s = "Aug" 
  Case 9 
   MonthName.s = "Sep" 
  Case 10 
   MonthName.s = "Okt" 
  Case 11 
   MonthName.s = "Nov" 
  Case 12 
   MonthName.s = "Dez" 
 EndSelect 
      
 ; Die Nachricht aus den Parametern im HTML-Format erstellen 
 Message.s = "<html>" + Chr(13)+Chr(10)+ "<head><title>" + Title.s + "</title></head>" + Chr(13)+Chr(10)+ "<body>" + Chr(13)+Chr(10)+ "<br><br><h1>" + Head.s + "</h1>" + "<br><br><br>" + Chr(13)+Chr(10)+ Text.s + Chr(13)+Chr(10)+ "<br><br><br><i>by(e) proxy...</ i>" + Chr(13)+Chr(10)+ "</body>" + Chr(13)+Chr(10)+ "</html>" 
  
 ; Und den HTTPHeader, der die Einleitung für die Nachricht gibt 
 HTTPHeader.s = "HTTP/1.1 OK" + Chr(13)+Chr(10)+ "Date: " + Tag.s + ", " + Str(DayOfWeek(Date())+1) + " " + MonthName.s + " " + FormatDate("%yyyy %hh:&ii:&ss", Date()) + Chr(13)+Chr(10)+ "Accept-Ranges: bytes" + Chr(13)+Chr(10)+ "Content-Length: " + Str(Len(Message.s)) + Chr(13)+Chr(10)+ "Connection: Keep-Alive" + Chr(13)+Chr(10)+ "Content- Type: text/html" + Chr(13)+Chr(10)+ Chr(13)+Chr(10) 
  
 ProcedureReturn (HTTPHeader.s + Message.s) 
EndProcedure;CreateServerMessage() 

;- Main 

OnErrorGoto(?CatchError) 

If InitNetwork() = 0 
 Fehlermeldung(#InitNetwork) 
 End 
EndIf;InitNetwork() = 0 

If CreateNetworkServer(0,Port) = 0 
 MessageRequester("Netzwerk-Fehler", "Netzwerk konnte nicht initialisiert werden !", 0) 
 MessageRequester(Fehler(#CreateNetworkServer)\Titel, Fehler(#CreateNetworkServer)\Text, 0) 
 Fehlermeldung(#CreateNetworkServer) 
 End 
EndIf;CreateNetworkServer() = 0 

InitFenster() 

Repeat 
  
 Gosub Proxy 
  
 WEvent = WindowEvent() 

 Select WEvent 
  
  Case #PB_Event_Gadget 
   Select EventGadget() 
    Case #cmdQuit : cmdQuit_Click()    
   EndSelect 
      
 EndSelect 

;Until Quit = 1 
Until WEvent = #PB_Event_CloseWindow 
MessageRequester("Ende", "Until EventID = #PB_Event_CloseWindow - erreicht", 0) 
;- Speicher muß noch freigegeben werden 
End  
  
;- *Proxy 
Proxy: 

 SEvent.l = NetworkServerEvent() 
;  0 : Nichts ist passiert 
;  1 : Ein neuer Client wurde mit dem Server verbunden 
;  2 : Roh-Daten wurden empfangen (können mittels ReceiveNetworkData() gelesen werden) 
;  3 : Eine Datei wurde empfangen (kann mittels ReceiveNetworkFile() gelesen werden) 
;  4 : Ein Client hat den Server verlassen (Verbindungstrennung) 

 If SEvent 
  
  ClientID.l = EventClient()  
  
  Select SEvent 
    
   Case 1 
    AddElement(ClientInfo()) 
    ClientInfo()\ClientID = ClientID.l 

   Case 2 
    Gosub ServerRohDatenVerarbeiten 
    
   Case 3 
;-  ServerDateiVerarbeiten existiert noch nicht 

   Case 4 
    ResetList(ClientInfo()) 
    While NextElement(ClientInfo()) 
     If ClientInfo()\ClientID = ClientID.l 
      DeleteElement(ClientInfo()) 
      Break 
     EndIf 
    Wend 
    
  EndSelect;SEvent 

 EndIf;SEvent 
  
    
 ;--- Kontrolliere ob was vom Webserver kommt. 
 ResetList(ClientInfo()) 
 While NextElement(ClientInfo()) 
    
  If ClientInfo()\WebserverID <> 0 
   CEvent.l = NetworkClientEvent(ClientInfo()\WebserverID) 
;    0 : Nichts ist passiert 
;    2 : Roh-Daten wurden empfangen (können mittels ReceiveNetworkData() gelesen werden) 
;    3 : Eine Datei wurde empfangen (kann mittels ReceiveNetworkFile() gelesen werden) 

   Select CEvent 

    Case 2 
     *ReceiveBuffer = AllocateMemory(61440) 
     ReceiveLaenge.l = ReceiveNetworkData(ClientInfo()\WebserverID, *ReceiveBuffer, 61440) ; Maximal 60KByte abholen 

     Debug "==================== Empfangen vom WebServer :" 
     Gosub MyDebug: 

     SendLaenge=SendNetworkData(ClientInfo()\ClientID, *ReceiveBuffer, ReceiveLaenge) a
     Debug "==================== und gesendet an Client :"      
     Debug "SendLaenge = " + Str(SendLaenge) + " und ReceiveLaenge = " + Str(ReceiveLaenge) 
     If ReceiveLaenge <> SendLaenge 
      MessageRequester("Error", "Fehler bei SendNetworkData() an Client", 0) 
     EndIf 
     FreeMemory(*ReceiveBuffer) 
     Delay(100)

    Case 3 
;-    ClientDateiVerarbeiten existiert noch nicht 

   EndSelect;CEvent 

  EndIf;ClientInfo()\WebserverID <> 0 
  
 Wend;NextElement(ClientInfo()) 
  
Return 



;- *RohDatenVerarbeiten 
ServerRohDatenVerarbeiten: 

 Source.s = "" 
 url.s = "" 
 Rest.s = "" 
 n.l = 0 
 i.l = 0 
 HTTPVersion.s = "" 
 Filepath.s = "" 
 FileTypes.s = "" 
 UserAgent.s = "" 
 Language.s = "" 
 Charset.s = "" 
 Encoding.s = "" 
 Connection.s = "" 
 Referer.s = "" 
 Command.s = "" 
 cookie.s = "" 
 Host.s = "" 
 Request.s = "" 
 d.s = "" 
  
 ResetList(ClientInfo()) 
 While NextElement(ClientInfo()) 
  If ClientInfo()\ClientID = ClientID.l 
   Break 
  EndIf 
 Wend 
 *ReceiveBuffer = AllocateMemory(61440) 
 ReceiveLaenge.l = ReceiveNetworkData(ClientID.l, *ReceiveBuffer, 61440) ; Maximal 60KByte abholen 

  Debug "==================== Empfangen vom ClientServer :" 
  Gosub MyDebug: 
    


; UB : gehe zunächst mal von Text (.s) aus 
  
 d.s = PeekS(*ReceiveBuffer) 
 Buffer.s = d.s 
 Buffer.s = LCase(Buffer) 
  
 ;--- Ob es ein Kommando ist, das modifiziert werden muss, oder nicht 
 If Left(Buffer.s, 3) <> "get" Or Left(Buffer.s, 4) = "post" 
  If ClientInfo()\WebserverID <> 0 
   SendNetworkData(ClientInfo()\WebserverID, *ReceiveBuffer, Len(PeekS(*ReceiveBuffer))) ; d.s) 
  EndIf 
 Else    

  Source.s = d.s 
      
  n.l = FindString(Source.s, Chr(13)+Chr(10), 0) 
  Request.s = Right(Source.s, Len(Source.s) - (n.l + 1)) 
  Command.s = Left(Source.s, n.l - 1) 
    
  If Left(Command.s, 3) = "GET" 
   ;--- wenn der Browser Daten will 
   n.l      = FindString(Command.s, " HTTP/", 0) 
   url.s     = Mid(Command.s, 5, Len(Command.s) - 4 - 9) 
   HTTPVersion.s = (Right(Command.s, 8) + Chr(13)+Chr(10)) 
   Buffer.s   = Right(url.s, Len(url.s) - 7) 
   Host.s    = Left(Buffer.s, FindString(Buffer.s, "/", 0) - 1) 
   Filepath.s  = Right(Buffer.s, Len(Buffer.s) - Len(Host.s)) 
   If FindString(Host.s, ":", 0) > 0 
    Port.l = Val(Mid(Host.s, FindString(Host.s, ":", 0) + 1, Len(Host.s))) 
    Host.s = Left(Host.s, FindString(Host.s, ":", 0) - 1) 
   Else 
    Port.l = 80 
   EndIf 
    
   ; Kommando einstellen 
   Command.s   = "GET" 
    
  ElseIf Left(Command.s, 4) = "POST" 
   ;--- wenn der Browser Daten schicken will 
   n.l      = FindString(Command.s, " HTTP/", 0) 
   url.s     = Mid(Command.s, 6, Len(Command.s) - 5 - 9) 
   HTTPVersion.s = (Right(Command.s, 8) + Chr(13)+Chr(10)) 
   Buffer.s   = Right(url.s, Len(url.s) - 7) 
   Host.s    = Left(Buffer.s, FindString(Buffer.s, "/", 0) - 1) 
   Filepath.s  = Right(Buffer.s, Len(Buffer.s) - Len(Host.s)) 
   If FindString(Host.s, ":", 0) > 0 
    Port.l = Val(Mid(Host.s, FindString(Host.s, ":", 0) + 1, Len(Host.s))) 
    Host.s = Left(Host.s, FindString(Host.s, ":", 0) - 1) 
   Else 
    Port.l = 80 
   EndIf 
    
   ; Kommando einstellen 
   Command.s   = "POST" 
  EndIf 
        
  ;--- Den Rest des HTTP-Requests aufspalten und die Informationen auswerten 
  Repeat 
   ; Solange wiederholen, Bis Request keine Zeilenumbrüche 
   ; mehr enthält 
   n.l = FindString(Request.s, Chr(13)+Chr(10), 0) 
   If n.l <> 0 
    Buffer.s = Left(Request.s, n.l - 1) 
    Request.s = Right(Request.s, Len(Request.s) - (n.l + 1)) 
    ; Buffer.s = Right(Buffer.s, Len(Buffer.s) - 1) 
    
    If Left(Buffer.s, 7) = "Accept:" 
     ;--- Die Datei-(MIME-)Typen, die der Browser akzeptiert 
     FileTypes.s = (Buffer.s + Chr(13)+Chr(10)) 
    ElseIf Left(Buffer.s, 16) = "Accept-Language:" 
     ;--- Die Sprache, Die neben Englisch noch akzeptiert wird 
     Language.s = (Buffer.s + Chr(13)+Chr(10)) 
    ElseIf Left(Buffer.s, 16) = "Accept-Encoding:" 
     ;--- Die Codierungen, Die akzeptiert werden 
     Encoding.s = (Buffer.s + Chr(13)+Chr(10)) 
    ElseIf Left(Buffer.s, 8) = "Referer:" 
     ;--- Der Referer (über welchen Link man die Seite aufgerufen hat) 
     Referer.s = (Buffer.s + Chr(13)+Chr(10)) 
    ElseIf Left(Buffer.s, 11) = "User-Agent:" 
     ; Der Browser-Typ 
     UserAgent.s = (Buffer.s + Chr(13)+Chr(10)) 
    ElseIf Left(Buffer.s, 7) = "Cookie:" 
     ; Der Browser-Typ 
     cookie.s = (Buffer.s + Chr(13)+Chr(10)) 
    ElseIf Left(Buffer.s, 5) = "Host:" 
     ; Der Browser-Typ 
     Host2.s = (Buffer.s + Chr(13)+Chr(10)) 
    ElseIf Left(Buffer.s, 17) = "Proxy-Connection:" 
     ; Ganz wichtig, Connection muss auf "Keep-Alive" stehen 
     Connection.s = ("Connection:" + Right(Buffer.s, Len(Buffer.s) - 17) + Chr(13)+Chr(10) + Chr(13)+Chr(10)) 
    EndIf 
   Else 
    Break 
   EndIf 
  ForEver 
      
  If HiddeReferer.l = 1 
   ; Referer austauschen (Verschleierung der Herkunft) 
   Referer.s = ("Referer: " + "www.google.de" + Chr(13)+Chr(10)) ; Zum Beispiel 
  EndIf 
  *tmpstr = AllocateMemory(61440) 
  ; http-Request zusammensetzen 
  Request.s = Command.s + " " + Filepath.s + " " + HTTPVersion.s + FileTypes.s + Encoding.s + Referer.s + Language.s + cookie.s + UserAgent.s + Host2.s + Connection.s 
  
  ; Wenn der Host immer noch der Gleiche und man noch immer mit ihm verbunden ist 
  If Host = ClientInfo()\Host And ClientInfo()\WebserverID <> 0 
   PokeS(*tmpstr, Request.s) 
   SendNetworkData(ClientInfo()\WebserverID, *tmpstr, Len(PeekS(*tmpstr))) 
  Else 
   If ClientInfo()\WebserverID <> 0 
    CloseNetworkConnection(ClientInfo()\WebserverID) 
   EndIf 
   ; Wenn der Webserver nicht erreichbar ist 
   ClientInfo()\WebserverID = OpenNetworkConnection(Host.s, Port.l) 
    
   If ClientInfo()\WebserverID = 0 
    ;--- Fehlernachricht an den Client senden 
    Buffer.s = CreateServerMessage(Host.s + " nicht erreichbar", Host.s + " nicht erreichbar.", "Der Remote-Computer " + Host.s + " ist nicht erreichbar. Stellen Sie sicher dass Sie mit dem Internet verbunden sind und dass der Remotehost online ist. Bitte nutzen Sie diesen Server nur als HTTP-Proxy.") 
    PokeS(*tmpstr, Buffer.s) 
    SendNetworkData(ClientInfo()\WebserverID, *tmpstr, Len(PeekS(*tmpstr))) 
   Else 
    PokeS(*tmpstr, Request.s) 
    SendNetworkData(ClientInfo()\WebserverID, *tmpstr, Len(PeekS(*tmpstr))) 
    ClientInfo()\Host = Host.s 
   EndIf 
  EndIf 
  FreeMemory(*tmpstr) 
  FreeMemory(*ReceiveBuffer) 
 EndIf 
Return 


;- Fehlerbehandlung 

xMyDebug: 
  If Len(PeekS(*ReceiveBuffer)) = ReceiveLaenge 
   Debug PeekS(*ReceiveBuffer) 
  Else 
   For k = 0 To ReceiveLaenge 
    B = PeekB(*ReceiveBuffer+k) 
    Debug "Byte " + RSet(Str(k),5,"0") + ":   " + RSet(Hex(B),2,"0") + "  " + RSet(StrU(B, #Byte),3,"0") + "  " + Str(B) 
   Next 
  EndIf 
Return 

MyDebug: 
Return 


CatchError: 
Msg$ = "There was an error:"+Chr(13)+Chr(10)+Chr(13)+Chr(10) 
Msg$ + "Description: " + GetErrorDescription()+Chr(13)+Chr(10) 
Msg$ + "Total number of errors: "+Str(GetErrorCounter())+Chr(13)+Chr(10) 
Msg$ + "Error in linenr: "+Str(GetErrorLineNR())+Chr(13)+Chr(10)+Chr(13)+Chr(10) 
Msg$ + "The program will end now." 

MessageRequester("Error!", Msg$) 

; Now end the program, because we can't jump back after OnErrorGoto() 
End 
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

I'm currently playing with this too, in consol mode so I can see what's happening. One other thing I notice is that where you had "Debug "Pas GET..." " you need to be passing that along to the web server. You are assuming that after the client sends a single buffer request that it doesn't need to do anything anymore. there might be more than one buffer to send.
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
oliv
User
User
Posts: 42
Joined: Sun Aug 24, 2003 10:11 am
Location: France

Post by oliv »

In facts, my usage is only to forward "GET" commands, so the 'Debug "Pas get" ' is just to inform if there is another thing than "GET" command, I never saw it.

I used the console too, but files permits to have a longer log.

Do you have better results than me ?
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

Okay, I did a quick and dirty hack of your code, chopped out the bits I didn't understand and put some others in. I thought it would clash more than it has, but I can run several browsers at the same time with this and they all seem to get only the data they need.

I'm posting this through it too! 8) (Doh, I had to turn it off for the "post" ing part... damn) Thanks for the code kick start, I've been wanting to do something like this.

Debugs to console, not to file [Updated again just now, performance improvement, still need to clean it up]

Code: Select all



;- **********     Declarations  ************************ 
; Constantes 
#Max = 1 
#BufferSize = 4096 
#ServerPort = 4444

; Structures 
Structure S_Server 
  Event.l 
  Port.l 
EndStructure 

Structure S_Client 
  ID.l 
  Buffer.l 
  CurBuffSize.l
  Host.s
  Path.s
  ProxyCon.l
EndStructure 


; Listes 
NewList Clients.S_Client() 


;- **********     Initialisations    **************** 

InitNetwork()
OpenConsole()

; Création du serveur 
If CreateNetworkServer(0, #ServerPort) = 0 
    MessageRequester("Net Listen Error", "Cannot create a server on port: " + Str(#ServerPort)) 
    End 
EndIf 

NetEventCount.q = 0
NetEvent.l = 0
HostStartPos.l = 0
HostEndPos.l = 0
ClientCon.l = 0
                     
Repeat       
    NetEvent = NetworkServerEvent() 
    
    NetEventCount = NetEventCount + 1
    
    If NetEvent 
        Select NetEvent
            Case #PB_NetworkEvent_Connect 
                AddElement(Clients()) 
                Clients()\ID = EventClient() 
                Clients()\Buffer = AllocateMemory(#BufferSize) 
                PrintN("Connect! ID Assigned: " + Str(Clients()\ID))

            Case #PB_NetworkEvent_Disconnect 

                 ResetList(Clients()) 
                 While NextElement(Clients()) 
                     If Clients()\ID = EventClient() 
                         CloseNetworkConnection(Clients()\ID) 
                         FreeMemory(Clients()\Buffer) 
                         DeleteElement(Clients()) 
                         PrintN("Disconnect client: " + Str(EventClient()))
                         Break 
                     EndIf 
                 Wend 
;                   
            Case #PB_NetworkEvent_Data 
                PrintN("Data")

                ResetList(Clients()) 
                While NextElement(Clients()) 
                   If Clients()\ID = EventClient() 
                       
                     Clients()\CurBuffSize = ReceiveNetworkData(Clients()\ID, Clients()\Buffer, #BufferSize) 
                     
                     TempBuf.s = PeekS(Clients()\Buffer,Clients()\CurBuffSize) 
                                         
                     PrintN(TempBuf)
                     
                     If PeekS(Clients()\Buffer,3) = "GET" 
                        ;Clients()\Path = Mid(TempBuf,5,FindString(TempBuf," ", 6) - 5) 
                        
                        HostStartPos = FindString(TempBuf,"Host: ", 1) + 6 
                        HostEndPos = FindString(TempBuf,#CRLF$, HostStartPos + 1)
                        
                        Clients()\Host = Mid(TempBuf,HostStartPos,HostEndPos - HostStartPos )
                        ;PrintN(Clients()\Path)
                        PrintN("Open Connection to: " + Clients()\Host)
                            
                        Clients()\ProxyCon = OpenNetworkConnection(Clients()\Host,80) 

  
                       If Clients()\ProxyCon 
                           SendNetworkData(Clients()\ProxyCon, Clients()\Buffer, Clients()\CurBuffSize) 
                       EndIf 
;                       
      
                    Else  ;client still sending so pass through
                        If ClientCon 
                            SendNetworkData(Clients()\ProxyCon, Clients()\Buffer, Clients()\CurBuffSize) 
                        EndIf
                    EndIf 

                EndIf 
            Wend 

          
        EndSelect 
    EndIf 
    
    
    ResetList(Clients()) 
    While NextElement(Clients()) 
        If Clients()\ProxyCon 
            If NetworkClientEvent(Clients()\ProxyCon) 
                Repeat 
                      Clients()\CurBuffSize = ReceiveNetworkData(Clients()\ProxyCon, Clients()\Buffer, #BufferSize) 
                      SendNetworkData(Clients()\ID, Clients()\Buffer, Clients()\CurBuffSize)
                      PrintN("Sending " + Str(Clients()\CurBuffSize) + " bytes of data to client " + Str(Clients()\ID)) 
                      ;Delay(50) 
                Until Clients()\CurBuffSize < #BufferSize 
            EndIf 
        EndIf 
    Wend 

    ;If NetEventCount % 5 = 0 
        Delay(10)
    ;EndIf
    
 ForEver
    
    
CloseConsole()

End 

Last edited by pdwyer on Mon Dec 17, 2007 3:04 pm, edited 1 time in total.
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

still a few bugs left :( One handle leak I found that crept into my code but wasn't in yours, as I deleted some lines that were needed :oops: . Some "referer" types pages aren't handled even though they are "GET"s so a couple of pages fail.

getting better though :D
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

IE seems like it might be opening new threads for new port connections to get pics etc. This would work better multi threaded so that if one download is slow it doesn't hold up others. It's kind of serialising everything.
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
oliv
User
User
Posts: 42
Joined: Sun Aug 24, 2003 10:11 am
Location: France

Post by oliv »

I just see a litle (What is the right word to say that ? :oops: ) your code and I think that crept you have is due to a part you removed :

Code: Select all

Clients()\Commande = RemoveString(Clients()\Commande,":80")
But it is not a clean way. This line is because some browsers tell which port to connect :
GET http://IP.IP.IP.IP:PORT/fezzf/dfz.htm HTTP/1.1
You must remove ":PORT"
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

Actually I chopped this:

Code: Select all


            If Clients()\Connexion 
                CloseNetworkConnection(Clients()\Connexion) 
            EndIf 

:lol: So the connection to the web server from the proxy never got cleaned up.

I didn't add port support deliberately as I wanted to get it running quickly, so I just assumed 80. I'll have another look when I get home to see what I can clean up and to see what you've posted above. I'd really like to get this running with threads, add "post" support etc.
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

fixed handle leak, can POST now. Still not multi threaded though.
Not as verbose either

Code: Select all



#Max = 1 
#BufferSize = 8192 
#ServerPort = 4444

; Structures 
Structure S_Server 
  Event.l 
  Port.l 
EndStructure 

Structure S_Client 
  ID.l 
  Buffer.l 
  CurBuffSize.l
  Host.s
  Path.s
  ProxyCon.l
EndStructure 


; Listes 
NewList Clients.S_Client() 

InitNetwork()
OpenConsole()

NetEventCount.q = 0
NetEvent.l = 0
HostStartPos.l = 0
HostEndPos.l = 0
ClientCon.l = 0


; Création du serveur 
If CreateNetworkServer(0, #ServerPort) = 0 
    MessageRequester("Net Listen Error", "Cannot create a server on port: " + Str(#ServerPort)) 
    End 
EndIf 

                     
Repeat       
    NetEvent = NetworkServerEvent() 
    
    NetEventCount = NetEventCount + 1
    
    If NetEvent 
        Select NetEvent
            Case #PB_NetworkEvent_Connect 
                AddElement(Clients()) 
                Clients()\ID = EventClient() 
                Clients()\Buffer = AllocateMemory(#BufferSize) 
                PrintN("Connect! ID Assigned: " + Str(Clients()\ID) + " (" + Str(ListIndex(Clients())) + ")")

            Case #PB_NetworkEvent_Disconnect 

                 ResetList(Clients()) 
                 While NextElement(Clients()) 
                     If Clients()\ID = EventClient() 
                         CloseNetworkConnection(Clients()\ID) 
                         If Clients()\ProxyCon 
                            CloseNetworkConnection(Clients()\ProxyCon) 
                         EndIf 
            
                         FreeMemory(Clients()\Buffer) 
                         DeleteElement(Clients()) 
                         PrintN("Disconnect client: " + Str(EventClient()) + " (" + Str(ListIndex(Clients())) + ")")
                         PrintN(Str(CountList(Clients()))+ " Connections remaining" )
                         Break 
                     EndIf 
                 Wend 
;                   
            Case #PB_NetworkEvent_Data 
                PrintN("Data")

                ResetList(Clients()) 
                While NextElement(Clients()) 
                   If Clients()\ID = EventClient() 
                       
                     Clients()\CurBuffSize = ReceiveNetworkData(Clients()\ID, Clients()\Buffer, #BufferSize) 
                     
                     TempBuf.s = PeekS(Clients()\Buffer,Clients()\CurBuffSize) 
                                         
                     ;PrintN(TempBuf)
                     
                     If PeekS(Clients()\Buffer,3) = "GET" Or PeekS(Clients()\Buffer,4) = "POST"  
                        ;Clients()\Path = Mid(TempBuf,5,FindString(TempBuf," ", 6) - 5) 
                        
                        HostStartPos = FindString(TempBuf,"Host: ", 1) + 6 
                        HostEndPos = FindString(TempBuf,#CRLF$, HostStartPos + 1)
                        
                        Clients()\Host = Mid(TempBuf,HostStartPos,HostEndPos - HostStartPos )
                        ;PrintN(Clients()\Path)
                        PrintN("Open Connection to: " + Clients()\Host)
                        
                        If Clients()\ProxyCon 
                            CloseNetworkConnection(Clients()\ProxyCon) 
                        EndIf   
                        Clients()\ProxyCon = OpenNetworkConnection(Clients()\Host,80) 

  
                       If Clients()\ProxyCon 
                           SendNetworkData(Clients()\ProxyCon, Clients()\Buffer, Clients()\CurBuffSize) 
                       EndIf 
;                       
      
                    Else  ;client still sending so pass through
                        If ClientCon 
                            SendNetworkData(Clients()\ProxyCon, Clients()\Buffer, Clients()\CurBuffSize) 
                        EndIf
                    EndIf 

                EndIf 
            Wend 

          
        EndSelect 
    EndIf 
    
    
    ResetList(Clients()) 
    While NextElement(Clients()) 
        If Clients()\ProxyCon 
            If NetworkClientEvent(Clients()\ProxyCon) 
                Repeat 
                      Clients()\CurBuffSize = ReceiveNetworkData(Clients()\ProxyCon, Clients()\Buffer, #BufferSize) 
                      SendNetworkData(Clients()\ID, Clients()\Buffer, Clients()\CurBuffSize)
                      PrintN("Sending " + Str(Clients()\CurBuffSize) + " bytes of data to client " + Str(Clients()\ID) + " (" + Str(ListIndex(Clients())) + ")") 
                      ;Delay(50) 
                Until Clients()\CurBuffSize < #BufferSize 
            EndIf 
        EndIf 
    Wend 

    If NetEventCount % 2 = 0 
        Delay(10)
    EndIf
    
 ForEver
    
    
CloseConsole()

End 

Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
ADN2
New User
New User
Posts: 3
Joined: Thu Jan 17, 2008 10:24 pm

Post by ADN2 »

hi,

nice code but not work with big file :(
User avatar
pdwyer
Addict
Addict
Posts: 2813
Joined: Tue May 08, 2007 1:27 pm
Location: Chiba, Japan

Post by pdwyer »

how big is "big" ? I was doing downloads with the last version I created and some of them were of "reasonable" size :)

if you can point me at a failing url download I'll give it a try when I get home
Paul Dwyer

“In nature, it’s not the strongest nor the most intelligent who survives. It’s the most adaptable to change” - Charles Darwin
“If you can't explain it to a six-year old you really don't understand it yourself.” - Albert Einstein
Post Reply