Seite 1 von 2

ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 17:00
von ts-soft

Code: Alles auswählen

EnableExplicit

;====================== ReceiveHTTPMemory ============================
;  Author:                Thomas Schulz (ts-soft)
;  Date:                  January 13, 2011
;  Target OS:             All
;  Target Compiler:       Requires PureBasic 4.xx
;=====================================================================

Procedure.i ReceiveHTTPMemory(URL.s, BufferSize = 4096, Timeout = 5000)
  Protected Connection, Time, Time2, Event, Size, Size2, SizeAll, pos
  Protected.s Server
  Protected *Mem, *Buffer, *Mem2
  Size = 1

  If LCase(Left(URL, 7)) <> "http://" : URL = "http://" + URL : EndIf
  Server = GetURLPart(URL, #PB_URL_Site)
  If Not Server : ProcedureReturn #False : EndIf
  Connection = OpenNetworkConnection(Server, 80, #PB_Network_TCP)
  If Not Connection : ProcedureReturn #False : EndIf
  If BufferSize <= 0 : BufferSize = 4096 : EndIf
  *Buffer = AllocateMemory(BufferSize)
  If Not *Buffer : ProcedureReturn #False : EndIf

  SendNetworkString(Connection, "GET " + URL + " HTTP/1.0" + #LFCR$ + #LFCR$)
  Time = ElapsedMilliseconds()
  Repeat
    Event = NetworkClientEvent(Connection)
    If Event = #PB_NetworkEvent_Data
      Repeat
        Size = ReceiveNetworkData(Connection, *Buffer, BufferSize)
        If Size > 0
          Time = ElapsedMilliseconds()
          SizeAll + Size
          *Mem = ReAllocateMemory(*Mem, SizeAll)
          If *Mem
            CopyMemory(*Buffer, *Mem + (SizeAll - Size), Size)
          Else
            CloseNetworkConnection(Connection)
            FreeMemory(*Buffer)
            ProcedureReturn #False
          EndIf
        EndIf
      Until Size <= 0
    EndIf
    Time2 = ElapsedMilliseconds() - Time
  Until Time2 > Timeout Or Size <= 0
  CloseNetworkConnection(Connection)
  FreeMemory(*Buffer)
  If Time2 > Timeout
    If *Mem : FreeMemory(*Mem) : EndIf
    ProcedureReturn #False
  EndIf
  pos = FindString(PeekS(*mem, -1, #PB_UTF8), #CRLF$ + #CRLF$, 1) - 1
  pos = Len(#CRLF$ + #CRLF$) + pos
  Size2 = MemorySize(*Mem) - pos
  *Mem2 = AllocateMemory(Size2)
  If *Mem2
    CopyMemory(*Mem + pos, *Mem2, Size2)
    FreeMemory(*Mem)
    ProcedureReturn *Mem2
  EndIf
  FreeMemory(*Mem)
  ProcedureReturn #False
EndProcedure

; example windows only
InitNetwork()
Define *mem
*mem = ReceiveHTTPMemory("http://www.realsource.de/images/favicon.ico")
If *mem
  If CatchImage(0, *mem)
    FreeMemory(*mem)
    OpenWindow(0, #PB_Ignore, #PB_Ignore, 640, 480, "test", #PB_Window_SystemMenu)
    SendMessage_(WindowID(0), #WM_SETICON, 0, ImageID(0))
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
  EndIf
EndIf
Gruß
Thomas
/edit
stargates hinweise berücksichtigt.

/edit2
tipp von Hex0r berücksichtig.
Ausserdem wird bei Timeout jetzt false zurückgegeben.

/edit3
Tipp von Nino berücksichtigt

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 17:08
von TomS
Danke für's teilen. :)

Code: Alles auswählen

; example cross platform
InitNetwork()
Define *mem
*mem = ReceiveHTTPMemory("http://www.realsource.de/images/favicon.ico")
If *mem
  CatchImage(0, *mem)
  FreeMemory(*mem)
  OpenWindow(0, #PB_Ignore, #PB_Ignore, 640, 480, "test", #PB_Window_SystemMenu)
  ImageGadget(0, 5, 5, ImageWidth(0), ImageHeight(0), ImageID(0), #PB_Image_Border) ; SendMessage_(WindowID(0), #WM_SETICON, 0, ImageID(0))
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
:wink:

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 17:12
von ts-soft
Danke, auch für das Crossplattform Beispiel, da war ich gerade zu Faul :roll:
Hab die Routine aber unter Linux getestet. Mac sollte auch gehen.

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 17:37
von Shardik
@Thomas,
Danke für Deine ReceiveHTTPMemory-Prozedur.

@TomS,
leider steckt der Teufel bei der Plattformunabhängigkeit im Detail. Während Dein

Code: Alles auswählen

ImageGadget(0, 5, 5, ImageWidth(0), ImageHeight(0), ImageID(0), #PB_Image_Border)
in Windows perfekt funktioniert, erhalte ich in Linux folgende Fehlermeldung
(PB 4.51 in andLinux/Kubuntu 9.04 x86 und PB 4.51 x64 in Suse Linux Enterprise Server 10 SP3 x64):
Zeile 70 - Das angegebene Image ist nicht initialisiert
Das Herunterladen der Icon-Datei in der Prozedur von Thomas funktioniert in Windows und Linux
perfekt, aber vielleicht kommt Linux mit dem Icon-Format nicht zurecht?

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 17:45
von TomS
Da ich weder Linux noch Mac habe, wirst du dich damit an die PB-Entwickler wenden müssen.
Kann schon sein, dass Linux mit dem Iconformat nicht klar kommt.
Probier's aus: http://www.pureattraction.eu/bitmapicon.bmp (moderne Kunst :mrgreen: )


EDIT:
CatchImage-Hilfe hat geschrieben:Das Bildformat kann im BMP-, Icon- (.ico, nur auf Windows) oder jedem anderen von der ImagePlugin Library unterstützten Format vorliegen.

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 17:50
von Shardik
Das Problem stellt CatchImage() dar, weil das .ico-Format nur von Windows unterstützt wird: :wink:
PureBasic-Hilfe zu CatchImage() hat geschrieben:Das Bild kann im BMP-, Icon- (.ico, nur auf Windows) oder jedem anderen Format vorliegen,
welches durch die ImagePlugin Library unterstützt wird. Ist das Laden des Bildes nicht möglich,
wird als 'Ergebnis' 0 zurückgegeben.
Edit: TomS war schneller... :lol:

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 17:51
von STARGÅTE
Wieso kommt mir dieser Code so bekannt vor ReceiveHTTPString()

Aber dein Code kann ja sogar Binär runterladen ^^

Aber eine Frage, wieso lädtst du erst mit ReceiveNetworkData() ein einen Zwischenspeicher, und nicht gleich in den erweiterten echten Speicher?
ReAllocateMemory() musst du ja eh, aber das CopyMemory() innerhalb der Schleife ist doch unnötig ...

Das du am schluss alles Kopierst ist klar, damit man eine gültige MemoryID hat.

Im Übrigen ist es schlecht "If Size" abzufragen denn:
"Wenn ein Fehler bei der Verbindung auftrat (Verbindung unterbrochen, Verbindung durch den Server beendet, etc.), wird 'Ergebnis' gleich -1 sein."
dann würdest du SizeAll - 1 ... usw. machen ...
EDIT: Ups das fehlte mir auch ^^

So sehe es dann aus:

Code: Alles auswählen

;[...]
  Repeat
    Event = NetworkClientEvent(Connection)
    If Event = #PB_NetworkEvent_Data
      Repeat
        *mem = ReAllocateMemory(*mem, SizeAll+BufferSize)
        Size = ReceiveNetworkData(Connection, *Mem+SizeAll, BufferSize)
        If Size > 0
          SizeAll + Size
        EndIf
      Until Size <= 0
      If SizeAll
        *mem = ReAllocateMemory(*mem, SizeAll)
      EndIf
    EndIf   
  Until ElapsedMilliseconds() - Time > Timeout Or Not Size
;[...]

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 18:01
von ts-soft
STARGÅTE hat geschrieben:Wieso kommt mir dieser Code so bekannt vor ReceiveHTTPString()
Ich hab hier auch einen Code, der von edel, kiffi und mir entwickelt wurde, aber weit vor Deinem Snippet :mrgreen:

Code: Alles auswählen

Procedure.s RemoteXMLString(url.s, buffersize.l = 1024, timeout.l = 3000)
  
  ; by edel
  ; modified by kiffi
  ; modified by ts-soft
  
  Protected cid.l, pos.l, headerlen.l, NetEvent.l, Buffer.l 
  Protected server.s, file.s, Header.s, response.s
  
  url = LCase(url)
  RemoveString(url, "http://", 1, 1)
  pos = FindString(url, "/", 0)
  If pos = 0
    server = url
    file   = "/"
  Else
    server = Left(url, pos - 1)
    file   = Right(url, Len(url) - pos + 1)
  EndIf
  cid = OpenNetworkConnection(server, 80, #PB_Network_TCP)
  If cid
    Header  = "GET "+ file + " HTTP/1.0"  + #CRLF$
    Header  + "Host: " + server           + #CRLF$
    Header  + "Accept: */*"               + #CRLF$
    Header  + "Connection: close"         + #CRLF$ + #CRLF$
    SendNetworkString(cid, Header)
    Buffer  = AllocateMemory(buffersize)
    timeout + ElapsedMilliseconds()
    Repeat
      NetEvent = NetworkClientEvent(cid)
      If NetEvent = #PB_NetworkEvent_Data
        Repeat
          headerlen = ReceiveNetworkData(cid, Buffer, buffersize)
          response  + PeekS(Buffer, headerlen, #PB_UTF8)
        Until headerlen = 0
        FreeMemory(Buffer)
        pos      = FindString(response, #CRLF$ + #CRLF$, 0) - 1
        pos      = Len(#CRLF$ + #CRLF$) + pos
        pos      = FindString(response, "<", pos) - 1
        response = Mid(response, pos, Len(response) - pos - 1)
        CloseNetworkConnection(cid)
        ProcedureReturn response
      EndIf
      If timeout < ElapsedMilliseconds()
        CloseNetworkConnection(cid)
        ProcedureReturn ""
      EndIf
    ForEver
    CloseNetworkConnection(cid)
  EndIf
  If Buffer
    FreeMemory(Buffer)
  EndIf
  ProcedureReturn ""
EndProcedure
Siehste die Ähnlichkeit? :mrgreen:

Danke für die Hinweise.

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 19:26
von HeX0R
Nett :allright:

Aber ich würde die time-Variable bei jedem Datenempfang neu setzen.
Ansonsten kommst du evtl. versehentlich in den Timeout, obwohl noch übertragen wird.

Re: ReceiveHTTPMemory einfach und Crossplattform

Verfasst: 13.01.2011 19:30
von DarkDragon
Hallo,

Ich bin schon die ganze Zeit am überlegen ob man sowas nicht geschickterweise etwas anders macht: z.B. könnte man Cookies oder allein schon die Headerfelder in einer Map verwalten, die man der Methode übergibt (Cookies werden dann auch aktualisiert und Headerfelder der Antwort werden zurückübergeben), allerdings fehlt mir momentan die Zeit dazu ;-) .