diff --git a/harbour/ChangeLog b/harbour/ChangeLog
index 7fe21e63c0..8939255d95 100644
--- a/harbour/ChangeLog
+++ b/harbour/ChangeLog
@@ -8,6 +8,38 @@
2009-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
*/
+2009-04-07 00:41 UTC+0200 Francesco Saverio Giudice (info/at/fsgiudice.com)
+ * harbour/contrib/examples/uhttpd/uhttpd.prg
+ + Added _HTTP_RESPONSE headers
+ * Renamed defineServerAdresses() function to defineServer()
+ as now define all _SERVER variables
+ * ParseRequest() now uses uhttpd_SplitUrl() to define URI parts
+ * Host now is defined according with RFC2616
+ * HRB session now is defined as UHTTPD-SESSION to avoid collision with
+ SESSION in cookies
+ ! uhttpd_AddHeader() renamed to uhttpd_SetHeader() to be conformed to
+ RFC2616 that wants that a header variable is defined only once.
+ See cookie.prg changes.
+ Headers now are contained in a Hash instead of an array
+ * fixed as per above also uhttpd_GetHeader() / uhttpd_DelHeader()
+
+ * harbour/contrib/examples/uhttpd/session.prg
+ * uhttpd_AddHeader() -> uhttpd_SetHeader()
+ * harbour/contrib/examples/uhttpd/cgifunc.prg
+ * in function uhttpd_SplitUrl() added URI hash field
+ + harbour/contrib/examples/uhttpd/cookie.prg
+ * To conform to RFC2616 now if Set-Cookie has more than one value than
+ is created a comma separated list of cookie-name=cookie-value
+ * uhttpd_AddHeader() -> uhttpd_SetHeader()
+
+ * harbour/contrib/examples/uhttpd/modules/info.prg
+ + Added _HTTP_RESPONSE display
+
+ * harbour/contrib/examples/uhttpd/modules/cookie.prg
+ * harbour/contrib/examples/uhttpd/modules/showcounter.prg
+ * harbour/contrib/examples/uhttpd/modules/tableservletdb.prg
+ * uhttpd_AddHeader() -> uhttpd_SetHeader()
+
2009-04-06 23:38 UTC+0200 Viktor Szakats (harbour.01 syenar hu)
* utils/hbmk2/hbmk2.prg
! Fixed to properly set errorlevels. For some reason I thought
diff --git a/harbour/contrib/examples/uhttpd/cgifunc.prg b/harbour/contrib/examples/uhttpd/cgifunc.prg
index 857b089f87..5ddeed8710 100644
--- a/harbour/contrib/examples/uhttpd/cgifunc.prg
+++ b/harbour/contrib/examples/uhttpd/cgifunc.prg
@@ -95,7 +95,7 @@ FUNCTION uhttpd_GetVars( cFields, cSeparator )
// with same name, then I will change it to an array
IF ( hb_HPos( hHashVars, cName ) ) > 0
IF !HB_ISARRAY( hHashVars[ cName ] )
- // Transoform it to array
+ // Transform it to array
hHashVars[ cName ] := { hHashVars[ cName ] }
ENDIF
aAdd( hHashVars[ cName ], xValue )
@@ -137,11 +137,13 @@ FUNCTION uhttpd_SplitUrl( cUrl )
LOCAL hUrl := hb_Hash()
LOCAL nPos, cTemp, cUserNamePassword, cHostnamePort
LOCAL cProto, cHost, cPort, nPort, cUser, cPass, cPath, cQuery, cFragment
+ LOCAL cUri
// Prevents case matching
hb_HSetCaseMatch( hUrl, FALSE )
cTemp := cUrl
+ cUri := ""
// Starting with
// http://[username:password@]hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]]
@@ -156,6 +158,8 @@ FUNCTION uhttpd_SplitUrl( cUrl )
cProto := ""
ENDIF
+ cUri += cProto + IIF( !Empty( cProto ), "://", "" )
+
// Now we have:
// [username:password@]hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]]
@@ -212,6 +216,8 @@ FUNCTION uhttpd_SplitUrl( cUrl )
// Now we have:
// hostname[:port][/path[/file[.ext]]
+ cUri += cTemp
+
// Search for Path part using / char from right
nPos := RAt( "/", cTemp )
IF nPos > 0
@@ -225,7 +231,7 @@ FUNCTION uhttpd_SplitUrl( cUrl )
ENDIF
// Now we have:
- // hostname[:port][/path[/file[.ext]]
+ // hostname[:port]
cHostnamePort := cTemp
@@ -252,6 +258,7 @@ FUNCTION uhttpd_SplitUrl( cUrl )
hb_hSet( hUrl, "PATH" , cPath )
hb_hSet( hUrl, "QUERY" , cQuery )
hb_hSet( hUrl, "FRAGMENT", cFragment )
+ hb_hSet( hUrl, "URI" , cURI )
// Prevents externals to add something else to this Hash
hb_HSetAutoAdd( hUrl, FALSE )
diff --git a/harbour/contrib/examples/uhttpd/cookie.prg b/harbour/contrib/examples/uhttpd/cookie.prg
index d3f7db580c..301571622d 100644
--- a/harbour/contrib/examples/uhttpd/cookie.prg
+++ b/harbour/contrib/examples/uhttpd/cookie.prg
@@ -67,6 +67,7 @@ RETURN uhttpd_Cookie():New( cDomain, cPath, nExpireDays, nExpireSecs )
CLASS uhttpd_Cookie
// Data for cookies
+ DATA aCookies INIT {} // Using an array to mantain order
DATA cDomain
DATA cPath INIT "/"
DATA cExpire
@@ -96,7 +97,7 @@ METHOD SetCookieDefaults( cDomain, cPath, nExpireDays, nExpireSecs ) CLASS uhttp
RETURN NIL
METHOD SetCookie( cCookieName, xValue, cDomain, cPath, cExpires, lSecure, lHttpOnly ) CLASS uhttpd_Cookie
- LOCAL cStr
+ LOCAL cStr, nPos, nCookies
DEFAULT cDomain TO ::cDomain
DEFAULT cPath TO ::cPath
@@ -105,7 +106,26 @@ METHOD SetCookie( cCookieName, xValue, cDomain, cPath, cExpires, lSecure, lHttpO
::lHttpOnly := lHttpOnly
- cStr := cCookieName + "=" + uhttpd_UrlEncode( hb_cStr( xValue ) )
+ IF !Empty( xValue )
+ // Search if a cookie already exists
+ // case sensitive
+ IF ( nPos := aScan( ::aCookies, {|e| e[ 1 ] == cCookieName } ) ) > 0
+ ::aCookies[ nPos ][ 2 ] := uhttpd_UrlEncode( hb_cStr( xValue ) )
+ ELSE
+ aAdd( ::aCookies, { cCookieName, uhttpd_UrlEncode( hb_cStr( xValue ) ) } )
+ ENDIF
+ ELSE
+ IF ( nPos := aScan( ::aCookies, {|e| e[ 1 ] == cCookieName } ) ) > 0
+ hb_aDel( ::aCookies, nPos, .T. )
+ ENDIF
+ ENDIF
+
+ // Rebuild cookie string as per RFC2616 (comma separated list)
+ cStr := ""
+ nCookies := Len( ::aCookies )
+ aEval( ::aCookies, {|e, i| cStr += e[ 1 ] + "=" + e[ 2 ] + IIF( i < nCookies, ",", "" ) } )
+
+ //cStr := cCookieName + "=" + uhttpd_UrlEncode( hb_cStr( xValue ) )
IF cDomain <> NIL
cStr += "; domain=" + cDomain
@@ -121,7 +141,8 @@ METHOD SetCookie( cCookieName, xValue, cDomain, cPath, cExpires, lSecure, lHttpO
ENDIF
// Send the header
- uhttpd_AddHeader( "Set-Cookie", cStr, FALSE )
+ //uhttpd_SetHeader( "Set-Cookie", cStr, FALSE )
+ uhttpd_SetHeader( "Set-Cookie", cStr )
RETURN NIL
diff --git a/harbour/contrib/examples/uhttpd/modules/cookie.prg b/harbour/contrib/examples/uhttpd/modules/cookie.prg
index 6a796a239f..50a58d2279 100644
--- a/harbour/contrib/examples/uhttpd/modules/cookie.prg
+++ b/harbour/contrib/examples/uhttpd/modules/cookie.prg
@@ -108,7 +108,7 @@ Pressing button you will redirect to /info page. Look at COOKIE values.
// Set a simple cookie
oCookie := uhttpd_CookieNew( "localhost", "/", 1, 0 )
oCookie:SetCookie( "mycookie", cCookie )
- uhttpd_AddHeader( "Location", "/info" )
+ uhttpd_SetHeader( "Location", "/info" )
//uhttpd_Write( "cookie set Go to info page" )
RETURN NIL
ENDIF
diff --git a/harbour/contrib/examples/uhttpd/modules/info.prg b/harbour/contrib/examples/uhttpd/modules/info.prg
index 664647bd7b..78eadf56f2 100644
--- a/harbour/contrib/examples/uhttpd/modules/info.prg
+++ b/harbour/contrib/examples/uhttpd/modules/info.prg
@@ -59,7 +59,7 @@
#include "common.ch"
#include "hbclass.ch"
-MEMVAR _SERVER, _REQUEST, _GET, _POST, _COOKIE, _SESSION, _HTTP_REQUEST
+MEMVAR _SERVER, _REQUEST, _GET, _POST, _COOKIE, _SESSION, _HTTP_REQUEST, _HTTP_RESPONSE
FUNCTION HRBMAIN()
LOCAL cHtml
@@ -76,21 +76,23 @@ STATIC FUNCTION ShowServerInfo()
//cHtml += "
If it is first time you see this page reload it to see cookies
"
cHtml += '
Return to Main Page
'
- cHtml += DisplayVars( _Server , "SERVER Vars" )
+ cHtml += DisplayVars( _Server , "SERVER Vars" )
cHtml += "
"
- cHtml += DisplayVars( _HTTP_REQUEST , "HTTP Headers" )
+ cHtml += DisplayVars( _HTTP_REQUEST , "HTTP Request Headers" )
cHtml += "
"
- cHtml += DisplayVars( _Get , "GET Vars" )
+ cHtml += DisplayVars( _HTTP_RESPONSE, "HTTP Response Headers" )
cHtml += "
"
- cHtml += DisplayVars( _Post , "POST Vars" )
+ cHtml += DisplayVars( _Get , "GET Vars" )
cHtml += "
"
- cHtml += DisplayVars( _Cookie , "COOKIE Vars" )
+ cHtml += DisplayVars( _Post , "POST Vars" )
cHtml += "
"
- //cHtml += DisplayVars( _Files , "FILE Vars" )
+ cHtml += DisplayVars( _Cookie , "COOKIE Vars" )
+ cHtml += "
"
+ //cHtml += DisplayVars( _Files , "FILE Vars" )
//cHtml += "
"
- cHtml += DisplayVars( _Request, "REQUEST Vars" )
+ cHtml += DisplayVars( _Request , "REQUEST Vars" )
cHtml += "
"
- cHtml += DisplayVars( _Session, "SESSION Vars" )
+ cHtml += DisplayVars( _Session , "SESSION Vars" )
cHtml += "
"
// Set a simple cookie
diff --git a/harbour/contrib/examples/uhttpd/modules/showcounter.prg b/harbour/contrib/examples/uhttpd/modules/showcounter.prg
index e4a16c9254..50fefd138e 100644
--- a/harbour/contrib/examples/uhttpd/modules/showcounter.prg
+++ b/harbour/contrib/examples/uhttpd/modules/showcounter.prg
@@ -78,19 +78,19 @@ FUNCTION HRBMAIN()
cHtml := CreateCounter( AllTrim( Str( Val( _REQUEST[ "w" ] ) ) ) )
//hb_ToOutDebug( hb_sprintf( "CreateCounter = %s", cHtml ) )
IF !Empty( cHtml )
- uhttpd_AddHeader( "Content-Type", "image/gif" )
- uhttpd_AddHeader( "Pragma", "no-cache" )
- uhttpd_AddHeader( "Content-Disposition", "inline; filename=counter" + LTrim( Str( hb_randomint( 100 ) ) ) + ".gif" )
+ uhttpd_SetHeader( "Content-Type", "image/gif" )
+ uhttpd_SetHeader( "Pragma", "no-cache" )
+ uhttpd_SetHeader( "Content-Disposition", "inline; filename=counter" + LTrim( Str( hb_randomint( 100 ) ) ) + ".gif" )
uhttpd_Write( cHtml )
ELSE
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
uhttpd_Write( "
Error: No image created
" )
ENDIF
ELSE
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
uhttpd_Write( "Error: no parameters passed
" )
ENDIF
diff --git a/harbour/contrib/examples/uhttpd/modules/tableservletdb.prg b/harbour/contrib/examples/uhttpd/modules/tableservletdb.prg
index fe5ab8ae7f..495abc5b92 100644
--- a/harbour/contrib/examples/uhttpd/modules/tableservletdb.prg
+++ b/harbour/contrib/examples/uhttpd/modules/tableservletdb.prg
@@ -111,16 +111,16 @@ FUNCTION HRBMAIN()
IF !Empty( cXml )
- uhttpd_AddHeader("Content-Type", "text/xml")
+ uhttpd_SetHeader( "Content-Type", "text/xml" )
// cache control
- uhttpd_AddHeader( "Cache-Control", "no-cache, must-revalidate" )
- uhttpd_AddHeader( "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" )
+ uhttpd_SetHeader( "Cache-Control", "no-cache, must-revalidate" )
+ uhttpd_SetHeader( "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" )
uhttpd_Write( cXml )
ELSE
- uhttpd_AddHeader("Content-Type", "text/xml")
+ uhttpd_SetHeader("Content-Type", "text/xml")
uhttpd_Write( '' )
uhttpd_Write( 'No Data' )
diff --git a/harbour/contrib/examples/uhttpd/session.prg b/harbour/contrib/examples/uhttpd/session.prg
index 6ccd4da1ba..fa02e571dd 100644
--- a/harbour/contrib/examples/uhttpd/session.prg
+++ b/harbour/contrib/examples/uhttpd/session.prg
@@ -844,23 +844,23 @@ METHOD SendCacheLimiter() CLASS uhttpd_Session
LOCAL dDate
DO CASE
CASE ::cCache_Limiter == 'nocache'
- //uhttpd_AddHeader( 'Expires', 'Thu, 19 Nov 1981 08:52:00 GMT' )
- uhttpd_AddHeader( 'Expires', uhttpd_DateToGMT( ,,-1, ) )
- uhttpd_AddHeader( 'Cache-Control', 'no-cache' )
- //uhttpd_AddHeader("Cache-Control", "no-store, no-cache, must-revalidate") // HTTP/1.1
- //uhttpd_AddHeader("Cache-Control", "post-check=0, pre-check=0", FALSE )
- uhttpd_AddHeader( 'Pragma', 'no-cache' )
+ //uhttpd_SetHeader( 'Expires', 'Thu, 19 Nov 1981 08:52:00 GMT' )
+ uhttpd_SetHeader( 'Expires', uhttpd_DateToGMT( ,,-1, ) )
+ uhttpd_SetHeader( 'Cache-Control', 'no-cache' )
+ //uhttpd_SetHeader("Cache-Control", "no-store, no-cache, must-revalidate") // HTTP/1.1
+ //uhttpd_SetHeader("Cache-Control", "post-check=0, pre-check=0", FALSE )
+ uhttpd_SetHeader( 'Pragma', 'no-cache' )
CASE ::cCache_Limiter == 'private'
- uhttpd_AddHeader( 'Expires', 'Thu, 19 Nov 1981 08:52:00 GMT' )
- uhttpd_AddHeader( 'Cache-Control', 'private, max-age=' + LTrim( Str( ::nCache_Expire * 60 ) ) )
+ uhttpd_SetHeader( 'Expires', 'Thu, 19 Nov 1981 08:52:00 GMT' )
+ uhttpd_SetHeader( 'Cache-Control', 'private, max-age=' + LTrim( Str( ::nCache_Expire * 60 ) ) )
IF hb_FGetDateTime( hb_argv(0), @dDate )
- uhttpd_AddHeader( 'Last-Modified', uhttpd_DateToGMT( dDate ) )
+ uhttpd_SetHeader( 'Last-Modified', uhttpd_DateToGMT( dDate ) )
ENDIF
CASE ::cCache_Limiter == 'public'
- uhttpd_AddHeader( 'Expires', uhttpd_DateToGMT( ,,, ::nCache_Expire * 60 ) )
- uhttpd_AddHeader( 'Cache-Control', 'public, max-age=' + LTrim( Str( ::nCache_Expire * 60 ) ) )
+ uhttpd_SetHeader( 'Expires', uhttpd_DateToGMT( ,,, ::nCache_Expire * 60 ) )
+ uhttpd_SetHeader( 'Cache-Control', 'public, max-age=' + LTrim( Str( ::nCache_Expire * 60 ) ) )
IF hb_FGetDateTime( hb_argv(0), @dDate )
- uhttpd_AddHeader( 'Last-Modified', uhttpd_DateToGMT( dDate ) )
+ uhttpd_SetHeader( 'Last-Modified', uhttpd_DateToGMT( dDate ) )
ENDIF
OTHERWISE
uhttpd_Die( "ERROR: Caching method " + ::cCache_Limiter + " not implemented." )
diff --git a/harbour/contrib/examples/uhttpd/uhttpd.prg b/harbour/contrib/examples/uhttpd/uhttpd.prg
index ac454ed87b..af8897d12c 100644
--- a/harbour/contrib/examples/uhttpd/uhttpd.prg
+++ b/harbour/contrib/examples/uhttpd/uhttpd.prg
@@ -230,9 +230,9 @@ STATIC s_hHandlers := { ;
STATIC s_hScriptAliases := { => }
STATIC s_hAliases := { => }
-THREAD STATIC t_cResult, t_nStatusCode, t_aHeader, t_cErrorMsg, t_oSession
+THREAD STATIC t_cResult, t_nStatusCode, /*t_aHeader,*/ t_cErrorMsg, t_oSession
-MEMVAR _SERVER, _GET, _POST, _COOKIE, _SESSION, _REQUEST, _HTTP_REQUEST, m_cPost
+MEMVAR _SERVER, _GET, _POST, _COOKIE, _SESSION, _REQUEST, _HTTP_REQUEST, _HTTP_RESPONSE, m_cPost
ANNOUNCE ERRORSYS
@@ -567,6 +567,7 @@ FUNCTION MAIN( ... )
IF hb_InetErrorCode( hListen ) != 0
? "Bind Error"
+ WAIT
ELSE
s_nLocalPort := hb_InetPort( hListen )
@@ -880,7 +881,7 @@ STATIC FUNCTION ProcessConnection()
LOCAL nMsecs, nParseTime, nPos, nThreadID
LOCAL lQuitRequest := FALSE
- PRIVATE _SERVER, _GET, _POST, _COOKIE, _SESSION, _REQUEST, _HTTP_REQUEST, m_cPost
+ PRIVATE _SERVER, _GET, _POST, _COOKIE, _SESSION, _REQUEST, _HTTP_REQUEST, _HTTP_RESPONSE, m_cPost
nThreadId := hb_threadID()
@@ -955,6 +956,8 @@ STATIC FUNCTION ProcessConnection()
BEGIN SEQUENCE
+ cRequest := NIL
+
/* receive query */
nLen := readRequest( hSocket, @cRequest )
@@ -968,22 +971,23 @@ STATIC FUNCTION ProcessConnection()
ELSEIF nLen == 0 /* connection closed */
ELSE
- //hb_ToOutDebug( "cRequest -- INIZIO --\n\r%s\n\rcRequest -- FINE --\n\r", cRequest )
+ //hb_ToOutDebug( "cRequest -- BEGIN --\n\r%s\n\rcRequest -- END --\n\r", cRequest )
_SERVER := HB_IHASH(); _GET := HB_IHASH(); _POST := HB_IHASH(); _COOKIE := HB_IHASH()
- _SESSION := HB_IHASH(); _REQUEST := HB_IHASH(); _HTTP_REQUEST := HB_IHASH(); m_cPost := NIL
+ _SESSION := HB_IHASH(); _REQUEST := HB_IHASH(); _HTTP_REQUEST := HB_IHASH(); _HTTP_RESPONSE := HB_IHASH()
+ m_cPost := NIL
t_cResult := ""
- t_aHeader := {}
+ //t_aHeader := {}
t_nStatusCode := 200
t_cErrorMsg := ""
- defineServerAdresses( hSocket )
+ defineServer( hSocket )
IF ParseRequest( cRequest )
- //hb_ToOutDebug( "_SERVER = %s,\n\r _GET = %s,\n\r _POST = %s,\n\r _REQUEST = %s,\n\r _HTTP_REQUEST = %s\n\r", hb_ValToExp( _SERVER ), hb_ValToExp( _GET ), hb_ValToExp( _POST ), hb_ValToExp( _REQUEST ), hb_ValToExp( _HTTP_REQUEST ) )
+ //hb_ToOutDebug( "_SERVER = %s,\n\r _GET = %s,\n\r _POST = %s,\n\r _REQUEST = %s,\n\r _HTTP_REQUEST = %s,\n\r _HTTP_RESPONSE = %s\n\r", hb_ValToExp( _SERVER ), hb_ValToExp( _GET ), hb_ValToExp( _POST ), hb_ValToExp( _REQUEST ), hb_ValToExp( _HTTP_REQUEST ), hb_ValToExp( _HTTP_RESPONSE ) )
cSend := uproc_default()
ELSE
- uhttpd_SetStatusCode( 400 )
+ //uhttpd_SetStatusCode( 400 )
cSend := MakeResponse()
ENDIF
@@ -994,7 +998,7 @@ STATIC FUNCTION ProcessConnection()
WriteToLog( cRequest )
// Destroy PRIVATE VARIABLES
- _SERVER := _GET := _POST := _COOKIE := _SESSION := _REQUEST := _HTTP_REQUEST := m_cPost := NIL
+ _SERVER := _GET := _POST := _COOKIE := _SESSION := _REQUEST := _HTTP_REQUEST := _HTTP_RESPONSE := m_cPost := NIL
ENDIF
@@ -1043,7 +1047,7 @@ STATIC FUNCTION ServiceConnection()
LOCAL nError := 500013
LOCAL lQuitRequest := FALSE
- PRIVATE _SERVER, _GET, _POST, _COOKIE, _SESSION, _REQUEST, _HTTP_REQUEST, m_cPost
+ PRIVATE _SERVER, _GET, _POST, _COOKIE, _SESSION, _REQUEST, _HTTP_REQUEST, _HTTP_RESPONSE, m_cPost
ErrorBlock( { | oError | uhttpd_DefError( oError ) } )
@@ -1125,16 +1129,17 @@ STATIC FUNCTION ServiceConnection()
//hb_ToOutDebug( "cRequest -- INIZIO --\n\r%s\n\rcRequest -- FINE --\n\r", cRequest )
_SERVER := HB_IHASH(); _GET := HB_IHASH(); _POST := HB_IHASH(); _COOKIE := HB_IHASH()
- _SESSION := HB_IHASH(); _REQUEST := HB_IHASH(); _HTTP_REQUEST := HB_IHASH(); m_cPost := NIL
+ _SESSION := HB_IHASH(); _REQUEST := HB_IHASH(); _HTTP_REQUEST := HB_IHASH(); _HTTP_RESPONSE := HB_IHASH()
+ m_cPost := NIL
t_cResult := ""
- t_aHeader := {}
+ //t_aHeader := {}
t_nStatusCode := 200
t_cErrorMsg := ""
- defineServerAdresses( hSocket )
+ defineServer( hSocket )
IF ParseRequest( cRequest )
- //hb_ToOutDebug( "_SERVER = %s,\n\r _GET = %s,\n\r _POST = %s,\n\r _REQUEST = %s,\n\r _HTTP_REQUEST = %s\n\r", hb_ValToExp( _SERVER ), hb_ValToExp( _GET ), hb_ValToExp( _POST ), hb_ValToExp( _REQUEST ), hb_ValToExp( _HTTP_REQUEST ) )
+ //hb_ToOutDebug( "_SERVER = %s,\n\r _GET = %s,\n\r _POST = %s,\n\r _REQUEST = %s,\n\r _HTTP_REQUEST = %s,\n\r _HTTP_RESPONSE = %s\n\r", hb_ValToExp( _SERVER ), hb_ValToExp( _GET ), hb_ValToExp( _POST ), hb_ValToExp( _REQUEST ), hb_ValToExp( _HTTP_REQUEST ), hb_ValToExp( _HTTP_RESPONSE ) )
define_Env( _SERVER )
ENDIF
// Error page served
@@ -1146,7 +1151,7 @@ STATIC FUNCTION ServiceConnection()
WriteToLog( cRequest )
// Destroy PRIVATE VARIABLES
- _SERVER := _GET := _POST := _COOKIE := _SESSION := _REQUEST := _HTTP_REQUEST := m_cPost := NIL
+ _SERVER := _GET := _POST := _COOKIE := _SESSION := _REQUEST := _HTTP_REQUEST := _HTTP_RESPONSE := m_cPost := NIL
ENDIF
@@ -1191,6 +1196,7 @@ STATIC FUNCTION ServiceConnection()
STATIC FUNCTION ParseRequest( cRequest )
LOCAL aRequest, aLine, nI, nJ, cI
LOCAL cReq, aVal, cFields, hVars
+ LOCAL hUrl
// RFC2616
aRequest := uhttpd_split( CR_LF, cRequest )
@@ -1202,6 +1208,8 @@ STATIC FUNCTION ParseRequest( cRequest )
IF LEN( aLine ) != 3 .OR. ;
( aLine[1] != "GET" .AND. aLine[1] != "POST" ) .OR. ; // Sorry, we support GET and POST only
LEFT( aLine[3], 5 ) != "HTTP/"
+ // Set status code
+ t_nStatusCode := 501 // Not Implemented
RETURN .F.
ENDIF
@@ -1210,25 +1218,20 @@ STATIC FUNCTION ParseRequest( cRequest )
_SERVER[ "REQUEST_URI" ] := aLine[2]
_SERVER[ "SERVER_PROTOCOL" ] := aLine[3]
- IF ( nI := AT( "?", _SERVER["REQUEST_URI"] ) ) > 0
- _SERVER[ "SCRIPT_NAME" ] := LEFT( _SERVER["REQUEST_URI"], nI - 1)
- _SERVER[ "QUERY_STRING" ] := SUBSTR( _SERVER["REQUEST_URI"], nI + 1)
+ hUrl := uhttpd_SplitUrl( _SERVER[ "REQUEST_URI" ] )
+
+ _SERVER[ "SCRIPT_NAME" ] := hUrl[ "URI" ]
+ _SERVER[ "QUERY_STRING" ] := hUrl[ "QUERY" ]
+
+ /*
+ IF ( nI := AT( "?", _SERVER[ "REQUEST_URI" ] ) ) > 0
+ _SERVER[ "SCRIPT_NAME" ] := LEFT( _SERVER[ "REQUEST_URI" ], nI - 1)
+ _SERVER[ "QUERY_STRING" ] := SUBSTR( _SERVER[ "REQUEST_URI" ], nI + 1)
ELSE
- _SERVER[ "SCRIPT_NAME" ] := _SERVER["REQUEST_URI"]
+ _SERVER[ "SCRIPT_NAME" ] := _SERVER[ "REQUEST_URI" ]
_SERVER[ "QUERY_STRING" ] := ""
ENDIF
-
- _SERVER[ "HTTP_ACCEPT" ] := ""
- _SERVER[ "HTTP_ACCEPT_CHARSET" ] := ""
- _SERVER[ "HTTP_ACCEPT_ENCODING" ] := ""
- _SERVER[ "HTTP_ACCEPT_LANGUAGE" ] := ""
- _SERVER[ "HTTP_CONNECTION" ] := ""
- _SERVER[ "HTTP_HOST" ] := ""
- _SERVER[ "HTTP_KEEP_ALIVE" ] := ""
- _SERVER[ "HTTP_REFERER" ] := ""
- _SERVER[ "HTTP_USER_AGENT" ] := ""
- _SERVER[ "HTTP_CACHE_CONTROL" ] := ""
- _SERVER[ "HTTP_COOKIE" ] := ""
+ */
FOR nI := 2 TO LEN( aRequest )
IF aRequest[nI] == ""; EXIT
@@ -1248,8 +1251,9 @@ STATIC FUNCTION ParseRequest( cRequest )
_SERVER[ "HTTP_" + STRTRAN( UPPER( LEFT( aRequest[nI], nJ - 1 ) ), "-", "_" ) ] := cI
EXIT
CASE "HOST"
- aVal := uhttpd_split( ":", aRequest[ nI ] )
- _SERVER[ "HTTP_" + STRTRAN( UPPER( aVal[ 1 ] ), "-", "_")] := AllTrim( aVal[ 2 ] )
+ //aVal := uhttpd_split( ":", aRequest[ nI ] )
+ //_SERVER[ "HTTP_" + STRTRAN( UPPER( aVal[ 1 ] ), "-", "_")] := AllTrim( aVal[ 2 ] )
+ _SERVER[ "HTTP_" + STRTRAN( UPPER( LEFT( aRequest[nI], nJ - 1 ) ), "-", "_" ) ] := cI
EXIT
CASE "CONTENT-TYPE"
CASE "CONTENT-LENGTH"
@@ -1271,6 +1275,21 @@ STATIC FUNCTION ParseRequest( cRequest )
ENDIF
NEXT
+ // check if Host field is provided
+ IF hb_HPos( _HTTP_REQUEST, "Host" ) == 0
+
+ // Try to determine Host name
+ IF !Empty( hUrl[ "HOST" ] )
+ _HTTP_REQUEST[ "Host" ] := hUrl[ "HOST" ]
+ ELSE
+ _HTTP_REQUEST[ "Host" ] := ""
+ // Set status code
+ t_nStatusCode := 400 // Bad Request
+ RETURN .F.
+ ENDIF
+
+ ENDIF
+
//hb_toOutDebug( "_HTTP_REQUEST: aRequest = %s, _HTTP_REQUEST = %s\n\r", hb_ValToExp( aRequest ), hb_ValToExp( _HTTP_REQUEST ) )
// GET
@@ -1306,18 +1325,18 @@ STATIC FUNCTION ParseRequest( cRequest )
//hb_toOutDebug( "COOKIE: cFields = %s, hVars = %s, _COOKIE = %s, _REQUEST = %s\n\r", cFields, hb_ValToExp( hVars ), hb_ValToExp( _COOKIE ), hb_ValToExp( _REQUEST ) )
+ // define _HTTP_RESPONSE
+ _HTTP_RESPONSE[ "X-Powered-By" ] := Version()
+ _HTTP_RESPONSE[ "Connection" ] := "Close"
+ _HTTP_RESPONSE[ "Content-Type" ] := "text/html; charset=UTF-8"
+ _HTTP_RESPONSE[ "Server" ] := APP_NAME + " " + APP_VERSION
+ //_HTTP_RESPONSE[ "Transfer-Encoding" ] := "chunked"
+
// Complete _SERVER
_SERVER[ "SERVER_NAME" ] := uhttpd_split( ":", _HTTP_REQUEST[ "HOST" ], 1 )[ 1 ]
- _SERVER[ "SERVER_SOFTWARE" ] := APP_NAME + " " + APP_VERSION + " (" + OS() + ")"
- _SERVER[ "SERVER_SIGNATURE" ] := "" + _SERVER[ "SERVER_SOFTWARE" ] + " Server at " + _SERVER[ "SERVER_NAME" ] + " Port " + _SERVER[ "SERVER_PORT" ] + ""
- _SERVER[ "DOCUMENT_ROOT" ] := s_cDocumentRoot
- _SERVER[ "SERVER_ADMIN" ] := "root@localhost" // TOFIX: put real user
_SERVER[ "SCRIPT_FILENAME" ] := STRTRAN( STRTRAN( _SERVER[ "DOCUMENT_ROOT" ] + _SERVER[ "SCRIPT_NAME" ], "//", "/" ), "\", "/" )
- _SERVER[ "GATEWAY_INTERFACE" ] := "CGI/1.1"
- _SERVER[ "SCRIPT_URL" ] := _SERVER["SCRIPT_NAME"]
- _SERVER[ "SCRIPT_URI" ] := "http://" + _HTTP_REQUEST[ "HOST" ] + _SERVER["SCRIPT_NAME"]
- _SERVER[ "PATH_INFO" ] := NIL
- _SERVER[ "PATH_TRANSLATED" ] := NIL
+ _SERVER[ "SCRIPT_URL" ] := _SERVER[ "SCRIPT_NAME" ]
+ _SERVER[ "SCRIPT_URI" ] := "http://" + _HTTP_REQUEST[ "HOST" ] + _SERVER[ "SCRIPT_NAME" ]
//hb_ToOutDebug( "_SERVER = %s\n\r", hb_ValToExp( _SERVER ) )
//hb_ToOutDebug( "_GET = %s\n\r", hb_ValToExp( _GET ) )
@@ -1325,26 +1344,28 @@ STATIC FUNCTION ParseRequest( cRequest )
//hb_ToOutDebug( "_COOKIE = %s\n\r", hb_ValToExp( _COOKIE ) )
//hb_ToOutDebug( "_SESSION = %s\n\r", hb_ValToExp( _SESSION ) )
//hb_ToOutDebug( "_HTTP_REQUEST = %s\n\r", hb_ValToExp( _HTTP_REQUEST ) )
+ //hb_ToOutDebug( "_HTTP_RESPONSE = %s\n\r", hb_ValToExp( _HTTP_RESPONSE ) )
// After defined all SERVER vars we can define a session
// SESSION - sessions ID is stored as a cookie value, normally as SESSIONID var name (this can be user defined)
- t_oSession := uhttpd_SessionNew( "SESSION", s_cSessionPath )
+ t_oSession := uhttpd_SessionNew( "UHTTPD-SESSION", s_cSessionPath )
t_oSession:Start()
-
RETURN .T.
STATIC FUNCTION MakeResponse()
- LOCAL cRet, cReturnCode
+ LOCAL cRet, cReturnCode, v
- uhttpd_AddHeader( "Connection", "close" )
+ //uhttpd_SetHeader( "X-Powered-By", Version() )
+
+ //uhttpd_SetHeader( "Connection", "close" )
IF uhttpd_GetHeader( "Location" ) != NIL
t_nStatusCode := 301
ENDIF
IF uhttpd_GetHeader( "Content-Type" ) == NIL
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
ENDIF
cRet := "HTTP/1.1 "
@@ -1360,13 +1381,19 @@ STATIC FUNCTION MakeResponse()
CASE 402
CASE 403
CASE 404
+ CASE 405
+ CASE 500
+ CASE 501
+ CASE 502
CASE 503
+ CASE 504
+ CASE 505
t_cResult := "" + cReturnCode + "
"
EXIT
// extended error messages - from Microsoft IIS Server
CASE 500013 // error: 500-13 Server too busy
- uhttpd_AddHeader( "Retry-After", "60" ) // retry after 60 seconds
+ uhttpd_SetHeader( "Retry-After", "60" ) // retry after 60 seconds
t_cResult := "500 Server Too Busy
"
EXIT
@@ -1380,14 +1407,25 @@ STATIC FUNCTION MakeResponse()
//hb_ToOutDebug( "_SESSION = %s\n\r", hb_ValToExp( _SESSION ) )
// Close session - Autodestructor will NOT close it, because t_oSession is destroyed only at end of Thread
- t_oSession:Close()
+
+ IF HB_ISOBJECT( t_oSession )
+ t_oSession:Close()
+ ENDIF
// t_oSession := NIL
WriteToConsole( cReturnCode )
cRet += cReturnCode + CR_LF
- AEVAL( t_aHeader, {|x| cRet += x[1] + ": " + x[2] + CR_LF } )
+
+ FOR EACH v IN _HTTP_RESPONSE
+ cRet += v:__enumKey() + ": " + v:__enumValue() + CR_LF
+ NEXT
+
+ //AEVAL( t_aHeader, {|x| cRet += x[1] + ": " + x[2] + CR_LF } )
cRet += CR_LF
cRet += t_cResult
+
+ //hb_ToOutDebug( "_HTTP_RESPONSE = %s\n\rcRet = %s\n\r", hb_ValToExp( _HTTP_RESPONSE ), cRet )
+
RETURN cRet
STATIC FUNCTION DecodeStatusCode()
@@ -1415,9 +1453,27 @@ STATIC FUNCTION DecodeStatusCode()
CASE 404
cReturnCode := "404 Not Found"
EXIT
+ CASE 405
+ cReturnCode := "405 Method Not Allowed"
+ EXIT
+ CASE 500
+ cReturnCode := "500 Internal Server Error"
+ EXIT
+ CASE 501
+ cReturnCode := "501 Not Implemented"
+ EXIT
+ CASE 502
+ cReturnCode := "502 Bad Gateway"
+ EXIT
CASE 503
cReturnCode := "503 Service Unavailable"
EXIT
+ CASE 504
+ cReturnCode := "504 Gateway Timeout"
+ EXIT
+ CASE 505
+ cReturnCode := "505 HTTP Version Not Supported"
+ EXIT
// extended error messages - from Microsoft IIS Server
CASE 500013 // error: 500-13 Server too busy
@@ -1676,31 +1732,49 @@ PROCEDURE uhttpd_SetStatusCode(nStatusCode)
RETURN
-PROCEDURE uhttpd_AddHeader( cType, cValue, lReplace )
- LOCAL nI
- DEFAULT lReplace TO TRUE // Needed from SetCookie()
+PROCEDURE uhttpd_SetHeader( cType, cValue )
+ //LOCAL nI
+ //DEFAULT lReplace TO TRUE // Needed from SetCookie()
+ hb_HSet( _HTTP_RESPONSE, cType, cValue )
+
+ /*
IF lReplace .AND. ( nI := ASCAN( t_aHeader, {|x| UPPER( x[ 1 ] ) == UPPER( cType ) } ) ) > 0
t_aHeader[ nI, 2 ] := cValue
ELSE
AADD( t_aHeader, { cType, cValue } )
ENDIF
+ */
+
RETURN
-FUNCTION uhttpd_GetHeader( cType, /*@*/ nPos )
+
+FUNCTION uhttpd_GetHeader( cType )
+ RETURN uhttpd_HGetValue( _HTTP_RESPONSE, cType )
+/*
DEFAULT nPos TO 1
+
+ nPos := hb_HPos( hHash, cKey ))
IF ( nPos := ASCAN( t_aHeader, {|x| UPPER( x[ 1 ] ) == UPPER( cType ) }, nPos ) ) > 0
RETURN t_aHeader[ nPos, 2 ]
ENDIF
RETURN NIL
+*/
PROCEDURE uhttpd_DelHeader( cType )
+ LOCAL nPos := hb_HPos( _HTTP_RESPONSE, cType )
+ IF nPos > 0
+ hb_HDel( _HTTP_RESPONSE, nPos )
+ ENDIF
+ RETURN
+/*
LOCAL nI
IF ( nI := ASCAN( t_aHeader, {|x| UPPER( x[ 1 ] ) == UPPER( cType ) } ) ) > 0
hb_aDel( t_aHeader, nI, TRUE )
ENDIF
RETURN
+*/
PROCEDURE uhttpd_Write( cString )
t_cResult += cString
@@ -1787,10 +1861,12 @@ STATIC FUNCTION sendReply( hSocket, cSend )
RETURN nError
-STATIC PROCEDURE defineServerAdresses( hSocket )
+STATIC PROCEDURE defineServer( hSocket )
#ifndef USE_HB_INET
LOCAL aI
#endif
+
+ // define _SERVER vars (address part)
#ifdef USE_HB_INET
_SERVER[ "REMOTE_ADDR" ] := hb_InetAddress( hSocket )
_SERVER[ "REMOTE_HOST" ] := _SERVER[ "REMOTE_ADDR" ] // no reverse DNS
@@ -1811,6 +1887,35 @@ STATIC PROCEDURE defineServerAdresses( hSocket )
ENDIF
#endif
+ // add other _SERVER vars
+ _SERVER[ "REQUEST_METHOD" ] := NIL
+ _SERVER[ "REQUEST_URI" ] := NIL
+ _SERVER[ "SERVER_PROTOCOL" ] := NIL
+ _SERVER[ "SCRIPT_NAME" ] := NIL
+ _SERVER[ "QUERY_STRING" ] := NIL
+ _SERVER[ "HTTP_ACCEPT" ] := NIL
+ _SERVER[ "HTTP_ACCEPT_CHARSET" ] := NIL
+ _SERVER[ "HTTP_ACCEPT_ENCODING" ] := NIL
+ _SERVER[ "HTTP_ACCEPT_LANGUAGE" ] := NIL
+ _SERVER[ "HTTP_CONNECTION" ] := NIL
+ _SERVER[ "HTTP_HOST" ] := NIL
+ _SERVER[ "HTTP_KEEP_ALIVE" ] := NIL
+ _SERVER[ "HTTP_REFERER" ] := ""
+ _SERVER[ "HTTP_USER_AGENT" ] := ""
+ _SERVER[ "HTTP_CACHE_CONTROL" ] := NIL
+ _SERVER[ "HTTP_COOKIE" ] := NIL
+ _SERVER[ "SERVER_NAME" ] := ""
+ _SERVER[ "SERVER_SOFTWARE" ] := APP_NAME + " " + APP_VERSION + " (" + OS() + ")"
+ _SERVER[ "SERVER_SIGNATURE" ] := "" + _SERVER[ "SERVER_SOFTWARE" ] + " Server at " + _SERVER[ "SERVER_NAME" ] + " Port " + _SERVER[ "SERVER_PORT" ] + ""
+ _SERVER[ "DOCUMENT_ROOT" ] := s_cDocumentRoot
+ _SERVER[ "SERVER_ADMIN" ] := "root@localhost" // TOFIX: put real user
+ _SERVER[ "SCRIPT_FILENAME" ] := NIL
+ _SERVER[ "GATEWAY_INTERFACE" ] := "CGI/1.1"
+ _SERVER[ "SCRIPT_URL" ] := NIL
+ _SERVER[ "SCRIPT_URI" ] := NIL
+ _SERVER[ "PATH_INFO" ] := NIL
+ _SERVER[ "PATH_TRANSLATED" ] := NIL
+
RETURN
FUNCTION uhttpd_split( cSeparator, cString, nMax )
@@ -1913,7 +2018,7 @@ STATIC FUNCTION uproc_default()
// if it exists as folder and it is missing trailing slash I add it and redirect to it
IF RIGHT( cFileName, 1 ) != "/"
- uhttpd_AddHeader( "Location", "http://" + _SERVER[ "HTTP_HOST" ] + _SERVER[ "SCRIPT_NAME" ] + "/" )
+ uhttpd_SetHeader( "Location", "http://" + _SERVER[ "HTTP_HOST" ] + _SERVER[ "SCRIPT_NAME" ] + "/" )
RETURN MakeResponse()
ENDIF
@@ -2020,7 +2125,7 @@ STATIC PROCEDURE Define_Env( hmServer )
STATIC PROCEDURE ShowServerStatus()
LOCAL cThreads
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
uhttpd_Write( '' )
uhttpd_Write( '' )
uhttpd_Write( '' )
@@ -2063,7 +2168,7 @@ STATIC PROCEDURE ShowFolder( cDir )
LOCAL aDir, aF
LOCAL cParentDir, nPos
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
aDir := DIRECTORY( uhttpd_OSFileName( cDir ), "D" )
IF HB_HHasKey( _GET, "s" )
@@ -2607,7 +2712,7 @@ STATIC FUNCTION Handler_Default( cFileName )
cMime := "application/octet-stream"
ENDIF
- uhttpd_AddHeader( "Content-Type", cMime )
+ uhttpd_SetHeader( "Content-Type", cMime )
uhttpd_Write( HB_MEMOREAD( uhttpd_OSFileName( cFileName ) ) )
// Directory content request
@@ -2635,7 +2740,7 @@ RETURN MakeResponse()
// This handler handle server status
STATIC FUNCTION Handler_ServerStatus()
LOCAL cThreads
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
uhttpd_Write( '' )
uhttpd_Write( '' )
uhttpd_Write( '' )
@@ -2715,7 +2820,7 @@ STATIC FUNCTION Handler_HrbScript( cFileName )
ENDIF
IF HB_ISSTRING( xResult )
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
uhttpd_Write( xResult )
ELSE
// Application in HRB module is responsible to send HTML content
@@ -2725,7 +2830,7 @@ STATIC FUNCTION Handler_HrbScript( cFileName )
WriteToConsole( "Error!" )
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
uhttpd_Write( "Error" )
uhttpd_Write( "
Description: " + hb_cStr( oError:Description ) )
uhttpd_Write( "
Filename: " + hb_cStr( oError:filename ) )
@@ -2748,13 +2853,13 @@ STATIC FUNCTION Handler_CgiScript( cFileName )
IF ( CGIExec( uhttpd_OSFileName(cFileName), @xResult ) ) == 0
- //uhttpd_AddHeader( "Content-Type", cI )
+ //uhttpd_SetHeader( "Content-Type", cI )
//uhttpd_Write( xResult )
RETURN "HTTP/1.1 200 OK " + CR_LF + xResult
ELSE
- uhttpd_AddHeader( "Content-Type", "text/html" )
+ uhttpd_SetHeader( "Content-Type", "text/html" )
IF !Empty( xResult )
uhttpd_Write( xResult )
ELSE