xHarbour can produce HTTP server ?

xHarbour can produce HTTP server ?

Postby dutch » Wed Nov 06, 2024 3:31 pm

Dear All,

I would like to make small program for waiting HTTP client GET api to request data?

I used to write HTTP client to POST to HTTP server only.

Thanks in advance for any help and idea.
Dutch
Regards,
Dutch

FWH 19.01 / xHarbour Simplex 1.2.3 / BCC73 / Pelles C / UEStudio
FWPPC 10.02 / Harbour for PPC (FTDN)
ADS V.9 / MySql / MariaDB
R&R 12 Infinity / Crystal Report XI R2
(Thailand)
User avatar
dutch
 
Posts: 1542
Joined: Fri Oct 07, 2005 5:56 pm
Location: Thailand

Re: xHarbour can produce HTTP server ?

Postby dutch » Thu Nov 07, 2024 1:20 am

I let ChatGPT produce sample code for HTTP server as below but it shows error.
I cannot work forward.

Code: Select all  Expand view  RUN
#include "fivewin.ch"
#include "hbsocket.ch"

Static oWnd

*-----------------*
FUNCTION Main()
DEFINE WINDOW oWnd FROM 0, 0 TO 800, 1000 PIXEL TITLE 'Http Server'

@  10, 10 BUTTON oBtn PROMPT 'Exit' SIZE 60, 30 PIXEL OF oWnd ACTION (oWnd:End())

ACTIVATE WINDOW oWnd ON INIT (HttpStart())
return

*---------------------*
Function HttpStart()
   LOCAL nPort := 8080
   LOCAL nSocket, nClientSocket, cRequest, cResponse
   
   // Initialize socket
   nSocket := SocketInit(nPort)
   IF nSocket < 0
      ? "Failed to initialize socket on port", nPort
      RETURN NIL
   ENDIF

   ? "Server started on port", nPort
   DO WHILE .T.
      nClientSocket := SocketAccept(nSocket)
      IF nClientSocket >= 0
         cRequest := SocketReadRequest(nClientSocket)
         ? "Received request:", cRequest

         // Determine if it's GET or POST
         IF LEFT(cRequest, 3) == "GET"
            cResponse := HandleGetRequest(cRequest)
         ELSEIF LEFT(cRequest, 4) == "POST"
            cResponse := HandlePostRequest(cRequest)
         ELSE
            cResponse := "HTTP/1.1 405 Method Not Allowed" + CRLF + ;
                         "Content-Length: 0" + CRLF + CRLF
         ENDIF

         // Send response to the client
         SocketSend(nClientSocket, cResponse)
         hb_SocketClose(nClientSocket)
      ENDIF
   ENDDO

   hb_SocketClose(nSocket)
   RETURN NIL


STATIC FUNCTION SocketInit(nPort)
   LOCAL nSocket := hb_socketOpen() // HB_SOCKET_AF_INET, HB_SOCKET_PT_STREAM, 0)
   IF nSocket < 0
      RETURN -1
   ENDIF

   hb_socketBind(nSocket, "0.0.0.0", nPort)
   hb_socketListen(nSocket, 5)
   RETURN nSocket

STATIC FUNCTION SocketAccept(nSocket)
   LOCAL nClientSocket := hb_socketAccept(nSocket)
   RETURN nClientSocket

STATIC FUNCTION SocketReadRequest(nClientSocket)
   LOCAL cRequest := hb_socketRecv(nClientSocket, 1024, 0)
   RETURN cRequest

STATIC FUNCTION HandleGetRequest(cRequest)
   LOCAL cResponse := "HTTP/1.1 200 OK" + CRLF + ;
                      "Content-Type: text/plain" + CRLF + ;
                      "Content-Length: 13" + CRLF + CRLF + ;
                      "Hello, World!"
   RETURN cResponse

STATIC FUNCTION HandlePostRequest(cRequest)
   LOCAL cBody := "Data received!"
   LOCAL cResponse := "HTTP/1.1 200 OK" + CRLF + ;
                      "Content-Type: text/plain" + CRLF + ;
                      "Content-Length: " + LTRIM(STR(LEN(cBody))) + CRLF + CRLF + ;
                      cBody
   RETURN cResponse
 
Regards,
Dutch

FWH 19.01 / xHarbour Simplex 1.2.3 / BCC73 / Pelles C / UEStudio
FWPPC 10.02 / Harbour for PPC (FTDN)
ADS V.9 / MySql / MariaDB
R&R 12 Infinity / Crystal Report XI R2
(Thailand)
User avatar
dutch
 
Posts: 1542
Joined: Fri Oct 07, 2005 5:56 pm
Location: Thailand

Re: xHarbour can produce HTTP server ?

Postby Otto » Thu Nov 07, 2024 7:28 am

Hello Dutch,
here nSocket returns a Pointer.
Have you looked at mod harbour?
Maybe it has these functions, and you could see how they are used.
Best regards,
Otto

Code: Select all  Expand view  RUN
STATIC FUNCTION SocketInit(nPort)
       LOCAL nSocket := hb_socketOpen() // HB_SOCKET_AF_INET, HB_SOCKET_PT_STREAM, 0)
     
      ? valtype(nSocket)
 
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
User avatar
Otto
 
Posts: 6334
Joined: Fri Oct 07, 2005 7:07 pm

Re: xHarbour can produce HTTP server ?

Postby dutch » Thu Nov 07, 2024 10:17 am

Dear Otto,

It's time to look at Mod Harbour. Thanks for investigate.
Otto wrote:Hello Dutch,
here nSocket returns a Pointer.
Have you looked at mod harbour?
Maybe it has these functions, and you could see how they are used.
Best regards,
Otto

Code: Select all  Expand view  RUN
STATIC FUNCTION SocketInit(nPort)
       LOCAL nSocket := hb_socketOpen() // HB_SOCKET_AF_INET, HB_SOCKET_PT_STREAM, 0)
     
      ? valtype(nSocket)
 
Regards,
Dutch

FWH 19.01 / xHarbour Simplex 1.2.3 / BCC73 / Pelles C / UEStudio
FWPPC 10.02 / Harbour for PPC (FTDN)
ADS V.9 / MySql / MariaDB
R&R 12 Infinity / Crystal Report XI R2
(Thailand)
User avatar
dutch
 
Posts: 1542
Joined: Fri Oct 07, 2005 5:56 pm
Location: Thailand

Re: xHarbour can produce HTTP server ?

Postby Lailton » Fri Nov 08, 2024 12:48 am

Can you explain what you want to do with more detail?
Then we can implement it on FiveWin.
Regards,
Lailton Fernando Mariano
User avatar
Lailton
 
Posts: 156
Joined: Fri Jul 20, 2012 1:49 am
Location: Brazil

Re: xHarbour can produce HTTP server ?

Postby dutch » Tue Nov 12, 2024 11:02 am

Dear Laiton,

My customer will use hotel tv and need me to integrate and I must be http server for waiting tv server request.
Lailton wrote:Can you explain what you want to do with more detail?
Then we can implement it on FiveWin.
Regards,
Dutch

FWH 19.01 / xHarbour Simplex 1.2.3 / BCC73 / Pelles C / UEStudio
FWPPC 10.02 / Harbour for PPC (FTDN)
ADS V.9 / MySql / MariaDB
R&R 12 Infinity / Crystal Report XI R2
(Thailand)
User avatar
dutch
 
Posts: 1542
Joined: Fri Oct 07, 2005 5:56 pm
Location: Thailand

Re: xHarbour can produce HTTP server ?

Postby Antonio Linares » Tue Nov 12, 2024 11:22 am

Dear Dutch,

To implement a web server using xHarbour you need to use multithreading and as far as I know it does not properly work with xHarbour

You need to use Harbour to do it, sorry. We have the Harbour code to do it, just in case.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: xHarbour can produce HTTP server ?

Postby dutch » Tue Nov 12, 2024 3:37 pm

Dear Antonio,

May I have sample of Harbour, I will try. Thanks
Antonio Linares wrote:Dear Dutch,

To implement a web server using xHarbour you need to use multithreading and as far as I know it does not properly work with xHarbour

You need to use Harbour to do it, sorry. We have the Harbour code to do it, just in case.
Regards,
Dutch

FWH 19.01 / xHarbour Simplex 1.2.3 / BCC73 / Pelles C / UEStudio
FWPPC 10.02 / Harbour for PPC (FTDN)
ADS V.9 / MySql / MariaDB
R&R 12 Infinity / Crystal Report XI R2
(Thailand)
User avatar
dutch
 
Posts: 1542
Joined: Fri Oct 07, 2005 5:56 pm
Location: Thailand

Re: xHarbour can produce HTTP server ?

Postby Antonio Linares » Tue Nov 12, 2024 8:39 pm

Dear Dutch,

Code: Select all  Expand view  RUN
#include "FiveWin.ch"
#include "inkey.ch"
#include "hbsocket.ch"

#define ADDRESS    "0.0.0.0"
#define PORT       80
#define TIMEOUT    30

//----------------------------------------------------------------//

CLASS HbWebServer

   DATA hListen
   DATA cAddress     INIT ADDRESS
   DATA nPort     INIT PORT
   DATA nTimeOut     INIT TIMEOUT

   DATA bOnGet
   DATA bOnPost

   METHOD Run( cAddress, nPort, nTimeOut )

ENDCLASS

//----------------------------------------------------------------//

METHOD Run( cAddress, nPort, nTimeOut ) CLASS HbWebServer

   #ifndef __XHARBOUR__
      local hSocket
   #endif

   DEFAULT cAddress := ::cAddress
   DEFAULT nPort := ::nPort
   DEFAULT nTimeOut := ::nTimeOut
   
   ::cAddress  := cAddress
   ::nPort     := nPort
   ::nTimeOut  := nTimeOut

   #ifndef __XHARBOUR__
      if ! hb_mtvm()
         // ? "HbWeb requires to build your Harbour app using hbmk2 -mt flag"
         return Self
      endif
   #else
      MsgAlert( "Class HbWebServer is not available in xHarbour" )  
   #endif  

   if Empty( ::hListen := hb_socketOpen() )
      // ? "HbWeb socket create error " + hb_ntos( hb_socketGetError() )
   endif

   //if ! hb_socketBind( ::hListen, { HB_SOCKET_AF_INET, ADDRESS, nPort } )
   if ! hb_socketBind( ::hListen, { HB_SOCKET_AF_INET, ::cAddress, ::nPort } )
      // ? "HbWeb bind error " + hb_ntos( hb_socketGetError() )
   endif

   if ! hb_socketListen( ::hListen )
      // ? "HbWeb listen error " + hb_ntos( hb_socketGetError() )
   endif

   // ? "HbWeb server running on port " + hb_ntos( PORT )

   #ifndef __XHARBOUR__
   while .T.
      //if Empty( hSocket := hb_socketAccept( ::hListen,, TIMEOUT ) )
      if Empty( hSocket := hb_socketAccept( ::hListen,, ::nTimeOut ) )
         if hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT
            // ? "loop"
         ELSE
            // ? "HbWeb accept error " + hb_ntos( hb_socketGetError() )
         endif
      ELSE
         // ? "HbWeb accept socket request"
         hb_threadDetach( hb_threadStart( @ServeClient(), Self, hSocket ) )
      endif
      if Inkey() == K_ESC
         // ? "HbWeb quitting - esc pressed"
         EXIT
      endif
   end
   #endif

   // ? "HbWeb close listening socket"

   hb_socketShutdown( ::hListen )
   hb_socketClose( ::hListen )

return nil

//----------------------------------------------------------------//

#ifndef __XHARBOUR__
static function ServeClient( oServer, hSocket, nTimeOut )

   local cRequest := ""
   local cBuffer
   local nLen     := 1
   local cAnswer := "<h1>Welcome to FWH WebServer<br>" + Time() + "</h1>"
   local cFileName
   local cData

   DEFAULT nTimeOut := TIMEOUT
   // ? "FWH WebServer new client connected"

   while nLen > 0
      cBuffer := Space( 1024 ^ 2 ) //4096 )
      //if ( nLen := hb_socketRecv( hSocket, @cBuffer,,, TIMEOUT ) ) > 0
      if ( nLen := hb_socketRecv( hSocket, @cBuffer,,, nTimeOut ) ) > 0
         cRequest += Left( cBuffer, nLen )
      else
         if nLen == -1 .and. hb_socketGetError() == HB_SOCKET_ERR_TIMEOUT
            nLen = 0
         endif
      endif
   end
   cBuffer  := ""

   if ! Empty( cRequest )
      // ? cRequest
      do case
         case ! Empty( oServer:bOnGet ) .and. Left( cRequest, 3 ) == "GET"
            cFileName = SubStr( cRequest, 6, At( "HTTP", cRequest ) - 6 )
            do case
               case ".css" $ cFileName
                  cData = hb_memoRead( cFileName )
                  hb_socketSend( hSocket, "HTTP/1.1 200 OK" + hb_OsNewLine() + ;
                                 "Content-type: text/css" + hb_OsNewLine() + ;
                                 hb_OsNewLine() + hb_OsNewLine() + ;
                                 cData )

               case ".png" $ cFileName
                  cData = hb_memoRead( cFileName )
                  hb_socketSend( hSocket, "HTTP/1.1 200 OK" + hb_OsNewLine() + ;
                                 "Content-type: image/png" + hb_OsNewLine() + ;
                                 "Content-Length: " + AllTrim( Str( Len( cData ) ) ) + ;
                                 hb_OsNewLine() + hb_OsNewLine() + ;
                                 cData )

               case ".jpg" $ cFileName
                  cData = hb_memoRead( cFileName )
                  hb_socketSend( hSocket, "HTTP/1.1 200 OK" + hb_OsNewLine() + ;
                                 "Content-type: image/jpg" + hb_OsNewLine() + ;
                                 "Content-Length: " + AllTrim( Str( Len( cData ) ) ) + ;
                                 hb_OsNewLine() + hb_OsNewLine() + ;
                                 cData )

               case ".bmp" $ cFileName
                  cData = hb_memoRead( cFileName )
                  hb_socketSend( hSocket, "HTTP/1.1 200 OK" + hb_OsNewLine() + ;
                                 "Content-type: image/png" + hb_OsNewLine() + ;
                                 "Content-Length: " + AllTrim( Str( Len( cData ) ) ) + ;
                                 hb_OsNewLine() + hb_OsNewLine() + ;
                                 cData )

               case ".ico" $ cAnswer //image/png
                  cData = hb_memoRead( cFileName )
                  hb_socketSend( hSocket, "HTTP/1.1 200 OK" + hb_OsNewLine() + ;
                                 "Content-type: image/x-icon" + hb_OsNewLine() + ;
                                 "Content-Length: " + AllTrim( Str( Len( cData ) ) ) + ;
                                 hb_OsNewLine() + hb_OsNewLine() + ;
                                 cData )
               otherwise                  
                  hb_socketSend( hSocket, "HTTP/1.1 200 OK" + hb_OsNewLine() + ;
                                    "Content-type: Text/html"  + hb_OsNewLine() + ;
                                    ; //"Access-Control-Allow-Origin: *" + ;
                                 hb_OsNewLine() + hb_OsNewLine() + ;
                                 Eval( oServer:bOnGet, cFileName ) )
            endcase                  

         case ! Empty( oServer:bOnPost ) .and. Left( cRequest, 4 ) == "POST"
            cAnswer = Eval( oServer:bOnPost, GetPostPairs( cRequest ) )
            hb_socketSend( hSocket, "HTTP/1.1 200 OK" + hb_OsNewLine() + ;
                           "Content-type: Text/html" + ;
                           hb_OsNewLine() + hb_OsNewLine() + cAnswer )            

      endcase
   endif

   hb_socketShutdown( hSocket )
   hb_socketClose( hSocket )

return nil
#endif

//----------------------------------------------------------------------------//

#ifndef __XHARBOUR__
static function GetPostPairs( cRequest, lUrlDecode )

   local cParams := SubStr( cRequest, At( hb_OsNewLine() + hb_OsNewLine(), cRequest ) + ;
                            Len( hb_OsNewLine() + hb_OsNewLine() ) )
   local aPairs := hb_ATokens( cParams, "&" )                        
   local cPair, uPair, hPairs := {=>}
   local nTable, aTable, cKey, cTag 

   DEFAULT lUrlDecode := .T.
   cTag = If( lUrlDecode, '[]', '%5B%5D' )

   for each cPair in aPairs
      if lUrlDecode
         cPair = hb_urlDecode( cPair )
      endif            

      if ( uPair := At( "=", cPair ) ) > 0   
         cKey = Left( cPair, uPair - 1 )   
         if ( nTable := At( cTag, cKey ) ) > 0     
            cKey = Left( cKey, nTable - 1 )        
            aTable = HB_HGetDef( hPairs, cKey, {} )                
            AAdd( aTable, SubStr( cPair, uPair + 1 ) )             
            hPairs[ cKey ] = aTable
         else                      
            hb_HSet( hPairs, cKey, SubStr( cPair, uPair + 1 ) )
         endif
      endif
   next

return hPairs
#endif

//----------------------------------------------------------------//

#ifndef __XHARBOUR__
static function ValToChar( u )

   local cType := ValType( u )
   local cResult

   do case
      case cType == "C" .or. cType == "M"
           cResult = u

      case cType == "D"
           cResult = DToC( u )

      case cType == "L"
           cResult = If( u, ".T.", ".F." )

      case cType == "N"
           cResult = AllTrim( Str( u ) )

      case cType == "A"
           cResult = hb_ValToExp( u )

      case cType == "O"
           cResult = ObjToChar( u )

      case cType == "P"
           cResult = "(P)"

      case cType == "S"
           cResult = "(Symbol)"
 
      case cType == "H"
           cResult = StrTran( StrTran( hb_JsonEncode( u, .T. ), hb_OsNewLine(), "<br>" ), " ", "&nbsp;" )
           if Left( cResult, 2 ) == "{}"
              cResult = StrTran( cResult, "{}", "{=>}" )
           endif  

      case cType == "U"
           cResult = "nil"

      otherwise
           cResult = "type not supported yet in function ValToChar()"
   endcase

return cResult  
#endif

//----------------------------------------------------------------//

#ifndef __XHARBOUR__
function ObjToChar( o )

   local hObj := {=>}, aDatas := __objGetMsgList( o, .T. )
   local hPairs := {=>}, aParents := __ClsGetAncestors( o:ClassH )

   AEval( aParents, { | h, n | aParents[ n ] := __ClassName( h ) } )

   hObj[ "CLASS" ] = o:ClassName()
   hObj[ "FROM" ]  = aParents

   AEval( aDatas, { | cData | ObjSetData( o, cData, hPairs ) } )
   hObj[ "DATAs" ]   = hPairs
   hObj[ "METHODs" ] = __objGetMsgList( o, .F. )

return ValToChar( hObj )
#endif

//----------------------------------------------------------------//

function ObjSetData( o, cData, hPairs )

   TRY
      hPairs[ cData ] := __ObjSendMsg( o, cData )
   CATCH      
      hPairs[ cData ] := "** protected **"
   END
   
return nil

//----------------------------------------------------------------//

#pragma BEGINDUMP

#include <hbapi.h>
#include <hbapierr.h>

HB_FUNC( HB_URLDECODE ) // Giancarlo's TIP_URLDECODE
{
   const char * pszData = hb_parc( 1 );

   if( pszData )
   {
      HB_ISIZ nLen = hb_parclen( 1 );

      if( nLen )
      {
         HB_ISIZ nPos = 0, nPosRet = 0;

         /* maximum possible length */
         char * pszRet = ( char * ) hb_xgrab( nLen );

         while( nPos < nLen )
         {
            char cElem = pszData[ nPos ];

            if( cElem == '%' && HB_ISXDIGIT( pszData[ nPos + 1 ] ) &&
                                HB_ISXDIGIT( pszData[ nPos + 2 ] ) )
            {
               cElem = pszData[ ++nPos ];
               pszRet[ nPosRet ]  = cElem - ( cElem >= 'a' ? 'a' - 10 :
                                            ( cElem >= 'A' ? 'A' - 10 : '0' ) );
               pszRet[ nPosRet ] <<= 4;
               cElem = pszData[ ++nPos ];
               pszRet[ nPosRet ] |= cElem - ( cElem >= 'a' ? 'a' - 10 :
                                            ( cElem >= 'A' ? 'A' - 10 : '0' ) );
            }
            else
               pszRet[ nPosRet ] = cElem == '+' ? ( char ) ' ' : cElem;

            nPos++;
            nPosRet++;
         }

         /* this function also adds a zero */
         /* hopefully reduce the size of pszRet */
         hb_retclen_buffer( ( char * ) hb_xrealloc( pszRet, nPosRet + 1 ), nPosRet );
      }
      else
         hb_retc_null();
   }
   else
      hb_errRT_BASE( EG_ARG, 3012, NULL,
                     HB_ERR_FUNCNAME, 1, hb_paramError( 1 ) );
}

#pragma ENDDUMP

//----------------------------------------------------------------//
 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Re: xHarbour can produce HTTP server ?

Postby Maurizio » Wed Nov 13, 2024 7:56 am

Hello Duch ,
I started from

C:\harbour\contrib\hbhttpd

Maurizio
User avatar
Maurizio
 
Posts: 825
Joined: Mon Oct 10, 2005 1:29 pm

Re: xHarbour can produce HTTP server ?

Postby wilsongamboa » Mon Nov 25, 2024 2:07 pm

Antonio
Example of use please ?
regards
Wilson
Wilson 'W' Gamboa A
Wilson.josenet@gmail.com
User avatar
wilsongamboa
 
Posts: 595
Joined: Wed Oct 19, 2005 6:41 pm
Location: Quito - Ecuador

Re: xHarbour can produce HTTP server ?

Postby Antonio Linares » Mon Nov 25, 2024 4:49 pm

Wilson,

FWH proporciona la función WebServer() en source\function\webapp.prg

Code: Select all  Expand view  RUN
function WebServer()

   local oServer := HbWebServer()

   if ! hb_HHasKey( hWebApp, "Dialogs" )
      hWebApp[ "Dialogs" ] = {}
   endif  

   oServer:bOnGet = { || Html() }

   oServer:Run()

return nil

 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42117
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 84 guests