WebClient (HttpRequest, HttpResponse)

Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Neue Antwort erstellen

Jolinah

Betreff: WebClient (HttpRequest, HttpResponse)

BeitragFr, Jun 22, 2007 13:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

hab ein paar Types geschrieben um den Download von Dateien oder Quellcodes von einem HTTP-Server zu vereinfachen. Der WebClient Type berücksichtigt auch Weiterleitungen und macht automatisch einen neuen Request auf die Weiterleitung.

Das ganze ist nur eine kleine Spielerei und ist nicht so optimiert, aber es funktioniert (einigermassen) Wink

HttpRequest stellt eine Anfrage an den Server dar. Mit der Methode GetResponse() erhält man dann ein HttpResponse-Objekt, welches die Antwort vom Server darstellt und Methoden bietet um die Antwort zu Speichern oder als String auszugeben.

WebClient ist sozusagen ein Wrapper, der die Benutzung mit HttpRequest und HttpResponse vereinfacht. Zusätzlich gibts noch 3 Beispiele (example1-3.bmx).

HttpRequest.bmx
Code: [AUSKLAPPEN]

'Sendet einen Request an einen HTTP-Server
Type HttpRequest
   Field RequestMethod:String
   Field HttpVersion:String
   Field URL:String
   Field Port:Int
   Field UserAgent:String
   Field PostContent:String
   Field Stream:TStream

   '--- HttpRequest erstellen ---
   Function Create:HttpRequest(URL:String, Port:Int = 80, RequestMethod:String = "GET", PostContent:String = "", HttpVersion:String = "HTTP/1.1")
      Local req:HttpRequest = New HttpRequest
      req.URL = URL
      req.Port = Port
      req.RequestMethod = RequestMethod.ToUpper()
      req.PostContent = PostContent
      req.HttpVersion = HttpVersion

      'Verbinden und Streamobjekt erstellen
      Local s:TSocket = TSocket.CreateTCP()

      If s <> Null Then
         If s.Connect(HostIp(req.GetHost()), Port) Then req.Stream = TSocketStream.Create(s)
         'Erste Zeile an Server senden (z.B. GET / HTTP/1.1)
         If req.Stream <> Null Then WriteLine(req.Stream, req.RequestMethod + " " + req.URL + " " + req.HttpVersion)
      EndIf
      
      Return req
   End Function
   
   
   '--- Einen zusätzlichen Header hinzufügen ---
   Method AddHeader(key:String, value:String)
      If Stream = Null Then Return
      'Wird direkt zum Server gesendet
      WriteLine(Stream, key + ": " + value)
   End Method
   

   '--- Aus der URL den Host rauslesen ---
   Method GetHost:String()
      If URL = "" Then Return ""
      'Teil zwischen http:// und dem nächsten Slash auslesen
      If Left(URL.ToLower(), 7) = "http://" Then
         Local pos:Int = Instr(URL, "/", 8)
         If pos > 0 Then
            Return Mid(URL.ToLower(), 8, pos - 8)
         Else
            Return Mid(URL.ToLower(), 8)
         EndIf
      EndIf
      Return ""
   End Method
   
   '--- HttpRequest durchführen und Antwort auslesen ---
   Method GetResponse:HttpResponse()
      If Stream = Null Then Return Null
      
      'Host-Header hinzufügen
      Local Host:String = GetHost()
      If Host <> "" Then AddHeader("Host", Host)

      'User-Agent-Header hinzufügen
      If UserAgent <> "" Then
         AddHeader("User-Agent", UserAgent)
      Else
         AddHeader("User-Agent", "BlitzMax Browser")
      EndIf
      
      'Content-Header hinzufügen
      If RequestMethod.ToUpper() = "POST"
         'Für POST muss der Content-Type so sein:
         AddHeader("Content-Type", "application/x-www-form-urlencoded")
         
         If PostContent <> "" Then
            AddHeader("Content-Length", PostContent.Length + 2)
         Else
            AddHeader("Content-Length", "0")
         EndIf
      EndIf
      
      'Header abschliessen
      WriteLine(Stream, "")
      
      'Bei POST den Content schreiben
      If RequestMethod.ToUpper() = "POST" And PostContent <> "" Then
         WriteLine(Stream, PostContent)
      EndIf

      'Antwort vom Stream auslesen
      Local res:HttpResponse = HttpResponse.Create(Stream)
      Return res
   End Method
   
End Type


HttpResponse.bmx
Code: [AUSKLAPPEN]

'Liest die Antwort von einem HTTP-Server aus
Type HttpResponse
   Field Status:Int
   Field ContentType:String
   Field ContentLength:Int
   Field Header:TMap
   Field Stream:TStream

   Method New()
      Header = New TMap
   End Method
   
   '--- Von einem Stream die Antwort auslesen und als HttpResponse-Objekt zurückgeben ---
   Function Create:HttpResponse(Stream:TStream)
      Local res:HttpResponse = New HttpResponse
      res.Stream = Stream
      
      If Stream = Null Then Return Null
      
      'Status-Code auslesen
      Local status:String = ReadLine(Stream)
      Local pos:Int = Instr(status, " ")
      If pos > 0 Then res.Status = Int(Mid(status, pos+1, 3))
      
      'Header auslesen und in TMap speichern
      While Not Eof(res.Stream)
         Local line:String = ReadLine(res.Stream)
         If line = "" Then Exit
         
         pos = Instr(line, ": ")
         If pos > 0 Then
            Local key:String = Mid(line, 1, pos-1)
            Local value:String = Mid(line, pos+2)
            res.Header.Insert(key.ToLower(), value)
            Select key.ToLower()
               Case "content-type"
                  res.ContentType = value
               Case "content-length"
                  res.ContentLength = Int(value)
            End Select
         EndIf
      Wend
      
      Return res
   End Function
   
   '--- Inhalt als String auslesen ---
   Method ContentString:String()
      Local ret:String = ""
      
      If ContentLength > 0 Then
      
         For Local i:Int = 0 To ContentLength - 1
            If TSocketStream(Stream)._socket.ReadAvail() < 1 Then Exit
            ret :+ Chr(ReadByte(Stream))
         Next
         
      Else
         
         Local read:Int = 0
         While TSocketStream(Stream)._socket.ReadAvail() > 0
            ret :+ Chr(ReadByte(Stream))
            read :+ 1
         Wend
      
      EndIf

      Stream.Close()
      Stream = Null
      
      Return ret
   End Method

   '--- Inhalt als Bank auslesen ---   
   Method ContentBank:TBank()
      Local Bank:TBank = Null
      
      If ContentLength > 0 Then
         Bank = TBank.Create(ContentLength)
      
         For Local i:Int = 0 To ContentLength - 1
            If TSocketStream(Stream)._socket.ReadAvail() < 1 Then Exit
            Bank.PokeByte(i, ReadByte(Stream))
         Next
         
      Else
         Bank = TBank.Create(0)
         
         Local read:Int = 0
         While TSocketStream(Stream)._socket.ReadAvail() > 0
            Bank.Resize(read+1)
            Bank.PokeByte(read, ReadByte(Stream))
            read :+ 1
         Wend
      
      EndIf

      Stream.Close()
      Stream = Null
      
      Return Bank
   End Method
   
   
   '--- Inhalt in eine Datei schreiben ---
   Method SaveContent:Int(Path:String)
      If Path = Null Or Path = "" Then Return False
      Local dir:String = ExtractDir(Path)
      If FileType(dir) = 0 Then CreateDir(dir, True)
      
      Local s:TStream = WriteFile(Path)
      If s = Null Then Return False
   
      Local b:Int = 0
      If ContentLength > 0 Then

         For Local i:Int = 0 To ContentLength - 1
            If TSocketStream(Stream)._socket.ReadAvail() < 1 Then Exit
            b = ReadByte(Stream)
            WriteByte(s, b)
         Next

      Else
      
         Local read:Int = 0
         While TSocketStream(Stream)._socket.ReadAvail() > 0
            b = ReadByte(Stream)
            WriteByte(s, b)
            read :+ 1
         Wend
      
      EndIf
      
      s.Close()
      s = Null
      Stream.Close()
      Stream = Null
      
      Return True
   End Method
   
End Type


WebClient.bmx
Code: [AUSKLAPPEN]

Include "HttpRequest.bmx"
Include "HttpResponse.bmx"

'Vereinfacht die Nutzung von HttpRequest und HttpResponse
Type WebClient

   '--- Einen Request machen der Weiterleitungen beachtet ---
   Function _DoRequest:HttpResponse(URL:String, Port:Int = 80)
      Local req:HttpRequest = HttpRequest.Create(URL, Port)
      Local res:HttpResponse = req.GetResponse()
      
      'Weiterleitungen beachten...
      Local redircount:Int = 0
      While res.Status >= 300 And res.Status <= 303 Or res.Status = 307
         'Bei mehr als 5 Weiterleitungen abbrechen (Gefahr einer Endlosschleife)
         redircount :+ 1
         If redircount > 5 Then Exit
         
         'Stream vom vorhergehenden Request schliessen
         res.Stream.Close()
         
         'Weiterleitung auslesen
         Local location:String = String(res.Header.ValueForKey("location"))
         If location = Null Or location = "" Then Exit

         'Port von Weiterleitung auslesen
         Local p:Int = Port
         Local pos:Int = 0
         If Left(location.ToLower(), 7) = "http://" Then pos = Instr(location, ":", 8)
         If pos > 0 Then
            Local pos2:Int = Instr(location, "/", pos+1)
            If pos2 > 0 Then
               p = Int(Mid(location, pos+1, pos2-pos-1))
            Else
               p = Int(Mid(location, pos+1))
            EndIf
         EndIf
         
         'Neuer Request zur Weiterleitung machen
         req = HttpRequest.Create(location, p)
         res = req.GetResponse()
      Wend
   
      Return res
   End Function
   
   
   '--- Seite bzw. Datei als String zurück geben ---
   Function GetString:String(URL:String, Port:Int = 80)
      Local res:HttpResponse = _DoRequest(URL, Port)
      Return res.ContentString()
   End Function
   
   '--- Seite bzw. Datei herunterladen (in einer lokalen Datei speichern) ---
   Function DownloadFile:Int(Path:String, URL:String, Port:Int = 80)
      Local res:HttpResponse = _DoRequest(URL, Port)
      Return res.SaveContent(Path)
   End Function
   
   '--- Seite bzw. Datei als Bank zurück geben ---
   Function GetBank:TBank(URL:String, Port:Int = 80)
      Local res:HttpResponse = _DoRequest(URL, Port)
      Return res.ContentBank()
   End Function

End Type


example1.bmx
Code: [AUSKLAPPEN]
SuperStrict

Include "WebClient.bmx"

'Ein kleiner Button
Type Button
   Field X:Int, Y:Int
   Field Width:Int, Height:Int
   Field Color:Int
   Field Text:String
   Field TextColor:Int
   Field OnClick() 'Callback-Funktion
   
   'Button erstellen
   Function Create:Button(X:Int, Y:Int, Width:Int, Height:Int, Text:String, Color:Int = $FFFFFF, TextColor:Int = 0)
      Local b:Button = New Button
      b.X = X
      b.Y = Y
      b.Width = Width
      b.Height = Height
      b.Text = Text
      b.Color = Color
      b.TextColor = TextColor
      Return b
   End Function
   
   'Button aktualisieren (auf Klick überprüfen)
   Method Update()
      Local mx:Int = MouseX()
      Local my:Int = MouseY()
      Local mh:Int = MouseHit(1)
      
      If mx > X And my > Y And mx < X + Width And my < Y + Height
         If mh Then
            'Beim anklicken wird die Callback-Funktion aufgerufen
            If OnClick <> Null Then OnClick()
         EndIf
      EndIf
   End Method
   
   'Button zeichnen
   Method Draw()
      SetColor((Color Shr 16) & $FF, (Color Shr 8) & $FF, Color & $FF)
      DrawRect X, Y, Width, Height
      SetColor((TextColor Shr 16) & $FF, (TextColor Shr 8) & $FF, TextColor & $FF)
      DrawText Text, X + Width / 2 - TextWidth(Text) / 2, Y + Height / 2 - TextHeight(Text) / 2
      SetColor(255, 255, 255)
   End Method
   
End Type


Graphics 800, 600, 0

'Bild das dynamisch geladen wird
Global img:TImage = Null

'Button
Local b:Button = Button.Create(100, 100, 150, 30, "Klick mich!", $FFFF00)
'Funktion die bei einem Klick ausgeführt wird setzen
b.OnClick = b_OnClick

'Hauptschleife
Repeat
Cls

   'Button aktualisieren und zeichnen
   b.Update()
   b.Draw()

   'Bild zeichnen wenn es vorhanden ist
   If img <> Null Then DrawImage img, 300, 100

Flip
Until KeyHit(KEY_ESCAPE)

EndGraphics
End


'Funktion die vom Button aus aufgerufen wird
Function b_OnClick()
   If img = Null Then
      'Bild mit dem Type WebClient herunterladen
      WebClient.DownloadFile("C:\english.png", "http://www.blitzforum.de/themes/Standard/english.png")
      'Bild von Festplatte laden
      img = LoadImage("C:\english.png")
   EndIf
End Function


example2.bmx
Code: [AUSKLAPPEN]
SuperStrict

Include "WebClient.bmx"

'Ein Formular automatisch ausfüllen (POST)
Local req:HttpRequest = HttpRequest.Create("http://tools.cybernet.ch/adslcheck/index.php", 80, "POST")

'Variablen des Formulars übergeben
req.PostContent = "requestedbc=06&tel=033 333 33 32&submit=prüfen"


'Antwort vom Server lesen
Local res:HttpResponse = req.GetResponse()

'Antwort lokal speichern und im Browser öffnen
If res.SaveContent("C:\response.html") Then
   OpenURL("C:\response.html")
EndIf

End


example3.bmx
Code: [AUSKLAPPEN]
SuperStrict

Include "WebClient.bmx"

'Mit WebClient ganz einfach den Quelltext einer Seite auslesen
Local text:String = WebClient.GetString("http://blitzforum.de/")
Print text

End

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Codearchiv & Module

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group