* contrib/hbhttpd/core.prg
* contrib/hbhttpd/widgets.prg
* contrib/hbpgsql/tests/cache.prg
* extras/hbxlsxml/xlsxml_s.prg
* extras/hbxlsxml/xlsxml_y.prg
* extras/hbxlsxml/xlsxml.prg
* extras/httpsrv/cgifunc.prg
* extras/httpsrv/cookie.prg
* extras/httpsrv/session.prg
* extras/httpsrv/uhttpd.prg
* src/rtl/dirscan.prg
% LTRIM(STR(x,y)) converted to hb_ntos() where y had
no significance or just limited the width unnecessarily
% ValType() usage converted to HB_IS*() or optimized
by rearragement of code or using SWITCH/CASE
858 lines
31 KiB
Plaintext
858 lines
31 KiB
Plaintext
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* uHTTPD (Micro HTTP server) cgi functions
|
|
*
|
|
* Copyright 2009 Francesco Saverio Giudice <info / at / fsgiudice.com>
|
|
* www - http://harbour-project.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
#include "error.ch"
|
|
#include "fileio.ch"
|
|
|
|
//#define HB_USE_HBTIP // Use functions from HBTIP - TOIMPLEMENT
|
|
|
|
#define CRLF ( Chr( 13 ) + Chr( 10 ) )
|
|
#xtranslate THROW( <oErr> ) => ( Eval( ErrorBlock(), <oErr> ), Break( <oErr> ) )
|
|
#define HB_IHASH() HB_HSETCASEMATCH( {=>}, .F. )
|
|
|
|
MEMVAR _SERVER, _GET, _POST, _COOKIE, _REQUEST, _HTTP_REQUEST
|
|
|
|
FUNCTION uhttpd_GetVars( cFields, cSeparator )
|
|
LOCAL hHashVars := { => }
|
|
LOCAL aField, cField, aFields
|
|
LOCAL cName, xValue
|
|
__defaultNIL( @cSeparator, "&" )
|
|
|
|
aFields := uhttpd_Split( cSeparator, cFields )
|
|
|
|
FOR EACH cField in aFields
|
|
aField := uhttpd_Split( "=", cField, 1 )
|
|
IF Len( aField ) == 1
|
|
hHashVars[ aField[ 1 ] ] := NIL
|
|
LOOP
|
|
ELSEIF Len( aField ) != 2
|
|
LOOP
|
|
ENDIF
|
|
|
|
cName := LTrim( aField[ 1 ] )
|
|
xValue := uhttpd_UrlDecode( aField[ 2 ] )
|
|
|
|
// Is it an array entry?
|
|
IF Substr( cName, Len( cName ) - 1 ) == "[]"
|
|
cName := Substr( cName, 1, Len( cName ) - 2 )
|
|
hHashVars[ cName ] := { xValue }
|
|
ELSE
|
|
// now check if variable already exists. If yes and I have already another element
|
|
// with same name, then I will change it to an array
|
|
IF ( hb_HPos( hHashVars, cName ) ) > 0
|
|
IF !HB_ISARRAY( hHashVars[ cName ] )
|
|
// Transform it to array
|
|
hHashVars[ cName ] := { hHashVars[ cName ] }
|
|
ENDIF
|
|
aAdd( hHashVars[ cName ], xValue )
|
|
ELSE
|
|
hHashVars[ cName ] := xValue
|
|
ENDIF
|
|
|
|
ENDIF
|
|
NEXT
|
|
|
|
RETURN hHashVars
|
|
|
|
/*
|
|
uhttpd_SplitUrl( cUrl ) --> hUrl
|
|
(C) 2006 Francesco Saverio Giudice
|
|
|
|
Splits a valid URL into simple components and return them in a hash
|
|
it works like parse_url() PHP function
|
|
|
|
a URL string is something like this:
|
|
http://[username:password@]hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]]
|
|
|
|
Parameters:
|
|
cUrl - Valid URL string
|
|
|
|
Returns:
|
|
hUrl - Hash containing these keys:
|
|
SCHEME - protocol name
|
|
HOST - hostname
|
|
PORT - protocol port number
|
|
USER - username
|
|
PASS - password
|
|
PATH - path to directory and/or file
|
|
QUERY - part after question mark ?
|
|
FRAGMENT - part after hashmark #
|
|
|
|
*/
|
|
FUNCTION uhttpd_SplitUrl( cUrl )
|
|
LOCAL hUrl := { => }
|
|
LOCAL nPos, cTemp, cUserNamePassword, cHostnamePort
|
|
LOCAL cProto, cHost, cPort, nPort, cUser, cPass, cPath, cQuery, cFragment
|
|
LOCAL cUri
|
|
|
|
// Prevents case matching
|
|
hb_HSetCaseMatch( hUrl, .F. )
|
|
|
|
cTemp := cUrl
|
|
cUri := ""
|
|
|
|
// Starting with
|
|
// http://[username:password@]hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]]
|
|
|
|
// Read protocol
|
|
nPos := At( "://", cTemp )
|
|
IF nPos > 0
|
|
cProto := Left( cTemp, nPos - 1 )
|
|
// delete protocol from temp string
|
|
cTemp := SubStr( cTemp, nPos + 3 )
|
|
ELSE
|
|
cProto := ""
|
|
ENDIF
|
|
|
|
cUri += cProto + iif( !Empty( cProto ), "://", "" )
|
|
|
|
// Now we have:
|
|
// [username:password@]hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]]
|
|
|
|
// Read username and password
|
|
nPos := At( "@", cTemp )
|
|
IF nPos > 0
|
|
cUserNamePassword := Left( cTemp, nPos - 1 )
|
|
// delete Username and Password from temp string
|
|
cTemp := SubStr( cTemp, nPos + 1 )
|
|
// Split username and password
|
|
nPos := At( ":", cUserNamePassword )
|
|
IF nPos > 0
|
|
cUser := Left( cUserNamePassword, nPos - 1 )
|
|
cPass := SubStr( cUserNamePassword, nPos + 1 )
|
|
ELSE
|
|
cUser := cUserNamePassword
|
|
cPass := ""
|
|
ENDIF
|
|
ELSE
|
|
cUser := ""
|
|
cPass := ""
|
|
ENDIF
|
|
|
|
// Now we have:
|
|
// hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]][#anchor]]
|
|
|
|
// Search for anchor using # char from right
|
|
nPos := RAt( "#", cTemp )
|
|
IF nPos > 0
|
|
cFragment := SubStr( cTemp, nPos + 1 )
|
|
|
|
// delete anchor from temp string
|
|
cTemp := SubStr( cTemp, 1, nPos - 1 )
|
|
|
|
ELSE
|
|
cFragment := ""
|
|
ENDIF
|
|
|
|
// Now we have:
|
|
// hostname[:port][/path[/file[.ext]][?arg1=[value][&arg2=[value]]]]
|
|
|
|
// Search for Query part using ? char from right
|
|
nPos := RAt( "?", cTemp )
|
|
IF nPos > 0
|
|
cQuery := SubStr( cTemp, nPos + 1 )
|
|
|
|
// delete query from temp string
|
|
cTemp := SubStr( cTemp, 1, nPos - 1 )
|
|
|
|
ELSE
|
|
cQuery := ""
|
|
ENDIF
|
|
|
|
// Now we have:
|
|
// hostname[:port][/path[/file[.ext]]
|
|
|
|
cUri += cTemp
|
|
|
|
// Search for Path part using / char from right
|
|
nPos := RAt( "/", cTemp )
|
|
IF nPos > 0
|
|
cPath := SubStr( cTemp, nPos )
|
|
|
|
// delete path from temp string
|
|
cTemp := SubStr( cTemp, 1, nPos - 1 )
|
|
|
|
ELSE
|
|
cPath := "/"
|
|
ENDIF
|
|
|
|
// Now we have:
|
|
// hostname[:port]
|
|
|
|
cHostnamePort := cTemp
|
|
|
|
// Searching port number
|
|
nPos := At( ":", cHostnamePort )
|
|
IF nPos > 0
|
|
cHost := Left( cHostnamePort, nPos - 1 )
|
|
cPort := SubStr( cHostnamePort, nPos + 1 )
|
|
nPort := Val( cPort )
|
|
IF nPort <= 0
|
|
nPort := -1
|
|
ENDIF
|
|
ELSE
|
|
cHost := cHostnamePort
|
|
nPort := -1
|
|
ENDIF
|
|
|
|
// Assemble hash
|
|
hb_hSet( hUrl, "SCHEME" , cProto )
|
|
hb_hSet( hUrl, "HOST" , cHost )
|
|
hb_hSet( hUrl, "PORT" , nPort )
|
|
hb_hSet( hUrl, "USER" , cUser )
|
|
hb_hSet( hUrl, "PASS" , cPass )
|
|
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, .F. )
|
|
RETURN hUrl
|
|
|
|
|
|
/*
|
|
uhttpd_SplitString( cString ) --> aLines
|
|
(C) 2006 Francesco Saverio Giudice
|
|
|
|
Splits a string into simple components and return them in an array
|
|
|
|
Parameters:
|
|
cString - Initial string
|
|
cDelim - Delimiter - default CRLF
|
|
lRemDelim - Remove delimiter from return values - default .T.
|
|
|
|
Returns:
|
|
aLines - Array with lines / fields for each element
|
|
|
|
Sample:
|
|
SplitString( "this=is=a=line=with=equals", "=" ) -> { "this", "is", "a", "line", "with", "equals" }
|
|
|
|
*/
|
|
FUNCTION uhttpd_SplitString( cString, cDelim, lRemDelim, nCount )
|
|
LOCAL nEOLPos
|
|
LOCAL cBuffer := cString
|
|
LOCAL aLines := {}, cLine
|
|
LOCAL nHowMany := 0
|
|
|
|
__defaultNIL( @cDelim, ( CHR( 13 ) + CHR( 10 ) ) )
|
|
__defaultNIL( @lRemDelim, .T. )
|
|
__defaultNIL( @nCount, -1 )
|
|
|
|
//WriteToLogFile( "Splitstring: " + cStr( cString ) )
|
|
|
|
DO WHILE ( nEOLPos := AT( cDelim, cBuffer ) ) > 0
|
|
nHowMany++
|
|
IF lRemDelim
|
|
cLine := LEFT( cBuffer, nEOLPos - 1 )
|
|
ELSE
|
|
cLine := LEFT( cBuffer, ( nEOLPos + LEN( cDelim ) ) - 1 )
|
|
ENDIF
|
|
//WriteToLogFile( "cBuffer, cDelim, nEOLPos, cLine: " + cStr( cBuffer ) + "," + cStr( cDelim ) + "," + cStr( nEOLPos ) + "," + cStr( cLine ) )
|
|
aAdd( aLines, cLine )
|
|
cBuffer := SubStr( cBuffer, nEOLPos + LEN( cDelim ) )
|
|
IF nCount > -1
|
|
IF nHowMany >= nCount
|
|
EXIT
|
|
ENDIF
|
|
ENDIF
|
|
ENDDO
|
|
|
|
// Check last line
|
|
IF Len( cBuffer ) > 0
|
|
aAdd( aLines, cBuffer )
|
|
ENDIF
|
|
|
|
RETURN aLines
|
|
|
|
/************************************************************
|
|
* Encoding URL
|
|
*/
|
|
FUNCTION uhttpd_URLEncode( cString, lComplete )
|
|
#ifdef HB_USE_HBTIP
|
|
__defaultNIL( @lComplete, .T. )
|
|
RETURN TIPENCODERURL_ENCODE( cString, lComplete )
|
|
#else
|
|
LOCAL cRet := "", i, nVal, cChar
|
|
|
|
__defaultNIL( @lComplete, .T. )
|
|
|
|
FOR i := 1 TO Len( cString )
|
|
cChar := SubStr( cString, i, 1)
|
|
DO CASE
|
|
CASE cChar == " "
|
|
cRet += "+"
|
|
|
|
CASE ( cChar >= "A" .AND. cChar <= "Z" ) .OR. ;
|
|
( cChar >= "a" .AND. cChar <= "z" ) .OR. ;
|
|
( cChar >= "0" .AND. cChar <= "9" ) .OR. ;
|
|
cChar == '.' .OR. cChar == ',' .OR. cChar == '&' .OR. ;
|
|
cChar == '/' .OR. cChar == ';' .OR. cChar == '_'
|
|
cRet += cChar
|
|
|
|
CASE iif( !lComplete, cChar == ':' .OR. cChar == '?' .OR. cChar == '=', .F. )
|
|
cRet += cChar
|
|
|
|
OTHERWISE
|
|
nVal := Asc( cChar )
|
|
cRet += "%" + hb_NumToHex( nVal )
|
|
ENDCASE
|
|
NEXT
|
|
RETURN cRet
|
|
|
|
/************************************************************
|
|
* Decoding URL
|
|
*/
|
|
FUNCTION uhttpd_URLDecode( cString )
|
|
#ifdef HB_USE_HBTIP
|
|
RETURN TIPENCODERURL_DECODE( cString )
|
|
#else
|
|
LOCAL cRet := "", i, cChar
|
|
|
|
FOR i := 1 TO Len( cString )
|
|
cChar := SubStr( cString, i, 1 )
|
|
DO CASE
|
|
CASE cChar == "+"
|
|
cRet += " "
|
|
|
|
CASE cChar == "%"
|
|
i ++
|
|
cRet += Chr( hb_HexToNum( SubStr( cString, i, 2 ) ) )
|
|
i ++
|
|
|
|
OTHERWISE
|
|
cRet += cChar
|
|
|
|
ENDCASE
|
|
|
|
NEXT
|
|
RETURN cRet
|
|
#endif
|
|
|
|
/*
|
|
* DateToGMT( dDate, cTime, nDayToAdd ) --> cGMTDate
|
|
*
|
|
* dDate : default DATE()
|
|
* cTime : default "00:00:00"
|
|
* nDayToAdd : default 0 - may be a negative number
|
|
*
|
|
* cGMTDate : The string return in form of "Saturday, 31-Oct-03 00:00:00 GMT"
|
|
*/
|
|
|
|
FUNCTION uhttpd_DateToGMT( dDate, cTime, nDayToAdd, nSecsToAdd )
|
|
LOCAL cStr
|
|
LOCAL cOldDateFormat := Set( _SET_DATEFORMAT, "dd-mm-yy" )
|
|
LOCAL nDay, nMonth, nYear, nDoW
|
|
LOCAL aDays := { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }
|
|
LOCAL aMonths := { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }
|
|
|
|
__defaultNIL( @dDate, DATE() )
|
|
__defaultNIL( @cTime, TIME() )
|
|
__defaultNIL( @nDayToAdd, 0 )
|
|
__defaultNIL( @nSecsToAdd, 0 )
|
|
|
|
//Tracelog( "DateToGMT - StartingValue", dDate, cTime, nDayToAdd, nSecsToAdd )
|
|
|
|
cTime := uhttpd_AddSecondsToTime( cTime, nSecsToAdd, @nDayToAdd )
|
|
dDate += nDayToAdd
|
|
|
|
nDay := Day( dDate )
|
|
nMonth := Month( dDate )
|
|
nYear := Year( dDate)
|
|
nDoW := Dow( dDate )
|
|
|
|
cStr := aDays[ nDow ] + ", " + StrZero( nDay, 2 ) + "-" + aMonths[ nMonth ] + "-" + ;
|
|
Right( StrZero( nYear, 4 ), 2 ) + " " + cTime + " GMT"
|
|
|
|
//Tracelog( "DateToGMT", cStr )
|
|
|
|
Set( _SET_DATEFORMAT, cOldDateFormat )
|
|
|
|
RETURN cStr
|
|
|
|
/*
|
|
* AddSecondsToTime( cTime, nSecsToAdd, @nDaysAdded ) --> cNewTime
|
|
*
|
|
* cTime : default "00:00:00"
|
|
* nSecsToAdd : default 0 - may be a negative number
|
|
* nDaysAdded : (out) return how many days add (or subtract) to actual date if numbers seconds is
|
|
* more than 86400 seconds (1 day)
|
|
*
|
|
* cNewTime : The new time string
|
|
*
|
|
* Rules: time is converted to seconds from midnight, then added of nSecsToAdd. Divided of 1 day and
|
|
* then reverted to Time string
|
|
*/
|
|
|
|
FUNCTION uhttpd_AddSecondsToTime( cTime, nSecsToAdd, nDaysAdded )
|
|
LOCAL nOneDaySeconds := 86400 // 24 * 60 * 60
|
|
LOCAL cNewTime, nSecs
|
|
|
|
__defaultNIL( @cTime, TIME() )
|
|
__defaultNIL( @nSecsToAdd, 0 )
|
|
// nDaysAdded can be already valued, so below i add to this value
|
|
__defaultNIL( @nDaysAdded, 0 )
|
|
|
|
IF nSecsToAdd != 0
|
|
nSecs := Secs( cTime ) + nSecsToAdd
|
|
nDaysAdded += Int( nSecs / nOneDaySeconds ) // Attention! nDaysAdded can be already filled
|
|
nSecs := nSecs - nDaysAdded
|
|
cNewTime := TSTRING( nSecs )
|
|
ELSE
|
|
cNewTime := cTime
|
|
ENDIF
|
|
|
|
RETURN cNewTime
|
|
|
|
FUNCTION uhttpd_TimeDiffAsSeconds( dDateStart, dDateEnd, cTimeStart, cTimeEnd )
|
|
LOCAL aRetVal
|
|
|
|
__defaultNIL( @dDateEnd, DATE() )
|
|
__defaultNIL( @cTimeEnd, TIME() )
|
|
|
|
aRetVal := FT_ELAPSED( dDateStart, dDateEnd, cTimeStart, cTimeEnd )
|
|
|
|
RETURN aRetVal[ 4, 2 ]
|
|
|
|
FUNCTION uhttpd_OutputString( cString, aTranslate, lProtected )
|
|
LOCAL cHtml
|
|
__defaultNIL( @lProtected, .F. )
|
|
__defaultNIL( @aTranslate, { { '"', '"' }, { ' ', ' ' } } )
|
|
|
|
//TraceLog( "OutputString( cString, aTranslate, lProtected )", cString, aTranslate, lProtected )
|
|
IF lProtected
|
|
cHtml := uhttpd_HtmlSpecialChars( cString )
|
|
ELSE
|
|
cHtml := uhttpd_TranslateStrings( cString, aTranslate )
|
|
ENDIF
|
|
//TraceLog( "OutputString() = cHtml", cHtml )
|
|
|
|
RETURN cHtml
|
|
|
|
FUNCTION uhttpd_HtmlSpecialChars( cString, cQuote_style )
|
|
LOCAL aTranslations := { ;
|
|
{ '&', '&' } ,;
|
|
{ '<', '<' } ,;
|
|
{ '>', '>' } ;
|
|
}
|
|
RETURN uhttpd_HtmlConvertChars( cString, cQuote_style, aTranslations )
|
|
|
|
FUNCTION uhttpd_HtmlConvertChars( cString, cQuote_style, aTranslations )
|
|
__defaultNIL( @cQuote_style, "ENT_COMPAT" )
|
|
DO CASE
|
|
CASE cQuote_style == "ENT_COMPAT"
|
|
aAdd( aTranslations, { '"', '"' } )
|
|
CASE cQuote_style == "ENT_QUOTES"
|
|
aAdd( aTranslations, { '"', '"' } )
|
|
aAdd( aTranslations, { "'", ''' } )
|
|
CASE cQuote_style == "ENT_NOQUOTES"
|
|
ENDCASE
|
|
RETURN uhttpd_TranslateStrings( cString, aTranslations )
|
|
|
|
FUNCTION uhttpd_CRLF2BR( cString )
|
|
LOCAL aTranslations := { ;
|
|
{ CRLF, '<br />' } ;
|
|
}
|
|
RETURN uhttpd_TranslateStrings( cString, aTranslations )
|
|
|
|
FUNCTION uhttpd_TranslateStrings( cString, aTranslate )
|
|
LOCAL aTran
|
|
FOR EACH aTran IN aTranslate
|
|
IF aTran[1] $ cString
|
|
cString := StrTran( cString, aTran[1], aTran[2] )
|
|
ENDIF
|
|
NEXT
|
|
RETURN cString
|
|
|
|
FUNCTION uhttpd_StrStr( cString, cSearch )
|
|
LOCAL nPos := AT( cSearch, cString )
|
|
LOCAL cVal := iif( nPos > 0, SubStr( cString, nPos ), NIL )
|
|
RETURN cVal
|
|
|
|
FUNCTION uhttpd_StrIStr( cString, cSearch )
|
|
RETURN uhttpd_StrStr( Upper( cSearch ), Upper( cString ) )
|
|
|
|
FUNCTION uhttpd_HtmlEntities( cString, cQuote_style )
|
|
// LOCAL aTranslations := { ; // ATTENTION, this chars are visible only with OEM font
|
|
// { hb_BChar( 160 ), ' ' } ,; // Nonbreaking space
|
|
// { hb_BChar( 161 ), '¡' } ,; // ¡ Inverted exclamation
|
|
// { hb_BChar( 162 ), '¢' } ,; // ¢ Cent sign
|
|
// { hb_BChar( 163 ), '£' } ,; // £ Pound sterling
|
|
// { hb_BChar( 164 ), '¤' } ,; // ¤ General currency sign
|
|
// { hb_BChar( 165 ), '¥' } ,; // ¥ Yen sign
|
|
// { hb_BChar( 166 ), '¦' } ,; // ¦ or &brkbar; Broken vertical bar
|
|
// { hb_BChar( 167 ), '§' } ,; // § Section sign
|
|
// { hb_BChar( 168 ), '¨' } ,; // ¨ or ¨ Diaeresis / Umlaut
|
|
// { hb_BChar( 169 ), '©' } ,; // © Copyright
|
|
// { hb_BChar( 170 ), 'ª' } ,; // ª Feminine ordinal
|
|
// { hb_BChar( 171 ), '«' } ,; // « Left angle quote, guillemet left
|
|
// { hb_BChar( 172 ), '¬' } ,; // ¬ Not sign
|
|
// { hb_BChar( 173 ), '­' } ,; // ­ Soft hyphen
|
|
// { hb_BChar( 174 ), '®' } ,; // ® Registered trademark
|
|
// { hb_BChar( 175 ), '¯' } ,; // ¯ or &hibar; Macron accent
|
|
// { hb_BChar( 176 ), '°' } ,; // ° Degree sign
|
|
// { hb_BChar( 177 ), '±' } ,; // ± Plus or minus
|
|
// { hb_BChar( 178 ), '²' } ,; // ² Superscript two
|
|
// { hb_BChar( 179 ), '³' } ,; // ³ Superscript three
|
|
// { hb_BChar( 180 ), '´' } ,; // ´ Acute accent
|
|
// { hb_BChar( 181 ), 'µ' } ,; // µ Micro sign
|
|
// { hb_BChar( 182 ), '¶' } ,; // ¶ Paragraph sign
|
|
// { hb_BChar( 183 ), '·' } ,; // · Middle dot
|
|
// { hb_BChar( 184 ), '¸' } ,; // ¸ Cedilla
|
|
// { hb_BChar( 185 ), '¹' } ,; // ¹ Superscript one
|
|
// { hb_BChar( 186 ), 'º' } ,; // º Masculine ordinal
|
|
// { hb_BChar( 187 ), '»' } ,; // » Right angle quote, guillemet right
|
|
// { hb_BChar( 188 ), '¼' } ,; // ¼ Fraction one-fourth
|
|
// { hb_BChar( 189 ), '½' } ,; // ½ Fraction one-half
|
|
// { hb_BChar( 190 ), '¾' } ,; // ¾ Fraction three-fourths
|
|
// { hb_BChar( 191 ), '¿' } ,; // ¿ Inverted question mark
|
|
// { hb_BChar( 192 ), 'À' } ,; // À Capital A, grave accent
|
|
// { hb_BChar( 193 ), 'Á' } ,; // Á Capital A, acute accent
|
|
// { hb_BChar( 194 ), 'Â' } ,; // Â Capital A, circumflex
|
|
// { hb_BChar( 195 ), 'Ã' } ,; // Ã Capital A, tilde
|
|
// { hb_BChar( 196 ), 'Ä' } ,; // Ä Capital A, diaeresis / umlaut
|
|
// { hb_BChar( 197 ), 'Å' } ,; // Å Capital A, ring
|
|
// { hb_BChar( 198 ), 'Æ' } ,; // Æ Capital AE ligature
|
|
// { hb_BChar( 199 ), 'Ç' } ,; // Ç Capital C, cedilla
|
|
// { hb_BChar( 200 ), 'È' } ,; // È Capital E, grave accent
|
|
// { hb_BChar( 201 ), 'É' } ,; // É Capital E, acute accent
|
|
// { hb_BChar( 202 ), 'Ê' } ,; // Ê Capital E, circumflex
|
|
// { hb_BChar( 203 ), 'Ë' } ,; // Ë Capital E, diaeresis / umlaut
|
|
// { hb_BChar( 204 ), 'Ì' } ,; // Ì Capital I, grave accent
|
|
// { hb_BChar( 205 ), 'Í' } ,; // Í Capital I, acute accent
|
|
// { hb_BChar( 206 ), 'Î' } ,; // Î Capital I, circumflex
|
|
// { hb_BChar( 207 ), 'Ï' } ,; // Ï Capital I, diaeresis / umlaut
|
|
// { hb_BChar( 208 ), 'Ð' } ,; // Ð Capital Eth, Icelandic
|
|
// { hb_BChar( 209 ), 'Ñ' } ,; // Ñ Capital N, tilde
|
|
// { hb_BChar( 210 ), 'Ò' } ,; // Ò Capital O, grave accent
|
|
// { hb_BChar( 211 ), 'Ó' } ,; // Ó Capital O, acute accent
|
|
// { hb_BChar( 212 ), 'Ô' } ,; // Ô Capital O, circumflex
|
|
// { hb_BChar( 213 ), 'Õ' } ,; // Õ Capital O, tilde
|
|
// { hb_BChar( 214 ), 'Ö' } ,; // Ö Capital O, diaeresis / umlaut
|
|
// { hb_BChar( 215 ), '×' } ,; // × Multiply sign
|
|
// { hb_BChar( 216 ), 'Ø' } ,; // Ø Capital O, slash
|
|
// { hb_BChar( 217 ), 'Ù' } ,; // Ù Capital U, grave accent
|
|
// { hb_BChar( 218 ), 'Ú' } ,; // Ú Capital U, acute accent
|
|
// { hb_BChar( 219 ), 'Û' } ,; // Û Capital U, circumflex
|
|
// { hb_BChar( 220 ), 'Ü' } ,; // Ü Capital U, diaeresis / umlaut
|
|
// { hb_BChar( 221 ), 'Ý' } ,; // Ý Capital Y, acute accent
|
|
// { hb_BChar( 222 ), 'Þ' } ,; // Þ Capital Thorn, Icelandic
|
|
// { hb_BChar( 223 ), 'ß' } ,; // ß Small sharp s, German sz
|
|
// { hb_BChar( 224 ), 'à' } ,; // à Small a, grave accent
|
|
// { hb_BChar( 225 ), 'á' } ,; // á Small a, acute accent
|
|
// { hb_BChar( 226 ), 'â' } ,; // â Small a, circumflex
|
|
// { hb_BChar( 227 ), 'ã' } ,; // ã Small a, tilde
|
|
// { hb_BChar( 228 ), 'ä' } ,; // ä Small a, diaeresis / umlaut
|
|
// { hb_BChar( 229 ), 'å' } ,; // å Small a, ring
|
|
// { hb_BChar( 230 ), 'æ' } ,; // æ Small ae ligature
|
|
// { hb_BChar( 231 ), 'ç' } ,; // ç Small c, cedilla
|
|
// { hb_BChar( 232 ), 'è' } ,; // è Small e, grave accent
|
|
// { hb_BChar( 233 ), 'é' } ,; // é Small e, acute accent
|
|
// { hb_BChar( 234 ), 'ê' } ,; // ê Small e, circumflex
|
|
// { hb_BChar( 235 ), 'ë' } ,; // ë Small e, diaeresis / umlaut
|
|
// { hb_BChar( 236 ), 'ì' } ,; // ì Small i, grave accent
|
|
// { hb_BChar( 237 ), 'í' } ,; // í Small i, acute accent
|
|
// { hb_BChar( 238 ), 'î' } ,; // î Small i, circumflex
|
|
// { hb_BChar( 239 ), 'ï' } ,; // ï Small i, diaeresis / umlaut
|
|
// { hb_BChar( 240 ), 'ð' } ,; // ð Small eth, Icelandic
|
|
// { hb_BChar( 241 ), 'ñ' } ,; // ñ Small n, tilde
|
|
// { hb_BChar( 242 ), 'ò' } ,; // ò Small o, grave accent
|
|
// { hb_BChar( 243 ), 'ó' } ,; // ó Small o, acute accent
|
|
// { hb_BChar( 244 ), 'ô' } ,; // ô Small o, circumflex
|
|
// { hb_BChar( 245 ), 'õ' } ,; // õ Small o, tilde
|
|
// { hb_BChar( 246 ), 'ö' } ,; // ö Small o, diaeresis / umlaut
|
|
// { hb_BChar( 247 ), '÷' } ,; // ÷ Division sign
|
|
// { hb_BChar( 248 ), 'ø' } ,; // ø Small o, slash
|
|
// { hb_BChar( 249 ), 'ù' } ,; // ù Small u, grave accent
|
|
// { hb_BChar( 250 ), 'ú' } ,; // ú Small u, acute accent
|
|
// { hb_BChar( 251 ), 'û' } ,; // û Small u, circumflex
|
|
// { hb_BChar( 252 ), 'ü' } ,; // ü Small u, diaeresis / umlaut
|
|
// { hb_BChar( 253 ), 'ý' } ,; // ý Small y, acute accent
|
|
// { hb_BChar( 254 ), 'þ' } ,; // þ Small thorn, Icelandic
|
|
// { hb_BChar( 255 ), 'ÿ' } ; // ÿ Small y, diaeresis / umlaut
|
|
// }
|
|
|
|
LOCAL aTranslations := {}
|
|
LOCAL i
|
|
FOR i := 160 TO 255
|
|
aAdd( aTranslations, { hb_BChar( i ), "&#" + Str( i, 3 ) + ";" } )
|
|
NEXT
|
|
|
|
RETURN uhttpd_HtmlConvertChars( cString, cQuote_style, aTranslations )
|
|
|
|
PROCEDURE uhttpd_Die( cError )
|
|
LOCAL oErr, lError
|
|
IF cError != NIL //THEN OutStd( cError )
|
|
//__OutDebug( "cError: ", cError )
|
|
//IF !oCGI:HeaderSent()
|
|
// oCGI:WriteLN( CRLF2BR( cError ), CRLF2BR( CRLF() ) )
|
|
// //oCGI:WriteLN( CRLF2BR( hb_dumpVar(TConfigure():hConfig) ) )
|
|
//ENDIF
|
|
// Generate Error
|
|
oErr := ErrorNew()
|
|
oErr:severity := ES_ERROR
|
|
oErr:genCode := EG_LIMIT
|
|
oErr:subSystem := "uhttpd_CGI"
|
|
oErr:subCode := 0
|
|
oErr:description := cError
|
|
oErr:canRetry := .F.
|
|
oErr:canDefault := .F.
|
|
oErr:fileName := ""
|
|
oErr:osCode := 0
|
|
lError := Eval( ErrorBlock(), oErr )
|
|
IF !HB_ISLOGICAL( lError ) .OR. lError
|
|
__ErrInHandler()
|
|
ENDIF
|
|
Break( oErr )
|
|
//QUIT
|
|
ELSE
|
|
QUIT
|
|
ENDIF
|
|
RETURN
|
|
|
|
FUNCTION uhttpd_HTMLSpace( n )
|
|
RETURN replicate( " ", n ) //" "
|
|
|
|
/* FROM FT LIB */
|
|
STATIC FUNCTION FT_ELAPSED(dStart, dEnd, cTimeStart, cTimeEnd)
|
|
LOCAL nTotalSec, nCtr, nConstant, nTemp, aRetVal[4,2]
|
|
|
|
IF HB_ISSTRING( dStart )
|
|
cTimeStart := dStart
|
|
dStart := DATE()
|
|
ELSEIF ! HB_ISDATE( dStart )
|
|
dStart := DATE()
|
|
ENDIF
|
|
|
|
IF HB_ISSTRING( dEnd )
|
|
cTimeEnd := dEnd
|
|
dEnd := DATE()
|
|
ELSEIF ! HB_ISDATE( dEnd )
|
|
dEnd := DATE()
|
|
ENDIF
|
|
|
|
iif( ! HB_ISSTRING( cTimeStart ), cTimeStart := '00:00:00', )
|
|
iif( ! HB_ISSTRING( cTimeEnd ) , cTimeEnd := '00:00:00', )
|
|
|
|
nTotalSec := (dEnd - dStart) * 86400 + ;
|
|
VAL(cTimeEnd) * 3600 + ;
|
|
VAL(SUBSTR(cTimeEnd,AT(':', cTimeEnd)+1,2)) * 60 + ;
|
|
iif(RAT(':', cTimeEnd) == AT(':', cTimeEnd), 0, ;
|
|
VAL(SUBSTR(cTimeEnd,RAT(':', cTimeEnd)+1))) - ;
|
|
VAL(cTimeStart) * 3600 - ;
|
|
VAL(SUBSTR(cTimeStart,AT(':', cTimeStart)+1,2)) * 60 - ;
|
|
iif(RAT(':', cTimeStart) == AT(':', cTimeStart), 0, ;
|
|
VAL(SUBSTR(cTimeStart,RAT(':', cTimeStart)+1)))
|
|
|
|
nTemp := nTotalSec
|
|
|
|
FOR nCtr := 1 to 4
|
|
nConstant := iif(nCtr == 1, 86400, iif(nCtr == 2, 3600, iif( nCtr == 3, 60, 1)))
|
|
aRetVal[nCtr,1] := INT(nTemp/nConstant)
|
|
aRetval[nCtr,2] := nTotalSec / nConstant
|
|
nTemp -= aRetVal[nCtr,1] * nConstant
|
|
NEXT
|
|
|
|
RETURN aRetVal
|
|
|
|
PROCEDURE uhttpd_WriteToLogFile( cString, cLog, lCreate )
|
|
LOCAL nHandle, cSep
|
|
|
|
cSep := hb_ps()
|
|
|
|
// __defaultNIL( @cLog, AppFullPath() + cSep + "logfile.log" )
|
|
__defaultNIL( @cLog, cSep + "tmp" + cSep + "logfile.log" )
|
|
__defaultNIL( @lCreate, .F. )
|
|
|
|
IF cLog != NIL
|
|
|
|
IF !lCreate .AND. hb_FileExists( cLog )
|
|
nHandle := FOpen( cLog, FO_READWRITE + FO_SHARED )
|
|
ELSE
|
|
nHandle := hb_FCreate( cLog, FC_NORMAL, FO_READWRITE + FO_SHARED )
|
|
//__OutDebug( "Create ", nHandle )
|
|
ENDIF
|
|
|
|
//cString := "PROCEDURE: " + ProcName( -2 ) + " " + cString
|
|
|
|
IF nHandle > 0
|
|
FSeek( nHandle, 0, FS_END )
|
|
FWrite( nHandle, cString )
|
|
FWrite( nHandle, CRLF )
|
|
FClose( nHandle )
|
|
ENDIF
|
|
ENDIF
|
|
RETURN
|
|
|
|
/*********************************************************************************/
|
|
|
|
FUNCTION uhttpd_SplitFileName( cFile )
|
|
LOCAL hFile
|
|
LOCAL cPath, cName, cExt, cDrive, cSep
|
|
|
|
HB_FnameSplit( cFile, @cPath, @cName, @cExt, @cDrive )
|
|
hFile := { ;
|
|
"FILE" => cFile ,;
|
|
"DRIVE" => cDrive ,;
|
|
"PATH" => cPath ,;
|
|
"NAME" => cName ,;
|
|
"EXT" => cExt ,;
|
|
"FULLPATH" => NIL ,;
|
|
"FULLNAME" => cName + cExt ,;
|
|
"UNC" => NIL ;
|
|
}
|
|
|
|
cSep := hb_ps()
|
|
|
|
hFile:FULLPATH := iif( !Empty( hFile:PATH ), iif( !( Right( hFile:PATH, Len( cSep ) ) == cSep ), hFile:PATH + cSep, hFile:PATH ), "" )
|
|
hFile:UNC := hFile:FULLPATH + hFile:FULLNAME
|
|
|
|
RETURN hFile
|
|
|
|
FUNCTION uhttpd_AppFullPath()
|
|
LOCAL hExeFile := uhttpd_SplitFileName( HB_ARGV(0) )
|
|
LOCAL cPrgFullPath := hExeFile:FULLPATH
|
|
LOCAL cPath, cSep
|
|
|
|
cSep := hb_ps()
|
|
|
|
IF Right( cPrgFullPath, Len( cSep ) ) == cSep
|
|
cPath := SubStr( cPrgFullPath, 1, Len( cPrgFullPath ) - Len( cSep ) )
|
|
ELSE
|
|
cPath := cPrgFullPath
|
|
ENDIF
|
|
RETURN cPath
|
|
|
|
FUNCTION uhttpd_AppFullName()
|
|
LOCAL hExeFile := uhttpd_SplitFileName( HB_ARGV(0) )
|
|
RETURN hExeFile:FULLNAME
|
|
|
|
|
|
FUNCTION uhttpd_CStrToVal( cExp, cType )
|
|
|
|
IF ! HB_ISSTRING( cExp )
|
|
Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) )
|
|
ENDIF
|
|
|
|
SWITCH cType
|
|
CASE 'C'
|
|
RETURN cExp
|
|
|
|
CASE 'P'
|
|
RETURN hb_HexToNum( cExp )
|
|
|
|
CASE 'D'
|
|
IF cExp[3] >= '0' .AND. cExp[3] <= '9' .AND. cExp[5] >= '0' .AND. cExp[5] <= '9'
|
|
RETURN sToD( cExp )
|
|
ELSE
|
|
RETURN cToD( cExp )
|
|
ENDIF
|
|
|
|
CASE 'L'
|
|
RETURN iif( cExp[1] == 'T' .OR. cExp[1] == 'Y' .OR. cExp[2] == 'T' .OR. cExp[2] == 'Y', .T., .F. )
|
|
|
|
CASE 'N'
|
|
RETURN Val( cExp )
|
|
|
|
CASE 'M'
|
|
RETURN cExp
|
|
|
|
CASE 'U'
|
|
RETURN NIL
|
|
|
|
/*
|
|
CASE 'A'
|
|
Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) )
|
|
|
|
CASE 'B'
|
|
Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) )
|
|
|
|
CASE 'O'
|
|
Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) )
|
|
*/
|
|
|
|
OTHERWISE
|
|
Throw( ErrorNew( "CSTR", 0, 3101, ProcName(), "Argument error", { cExp, cType } ) )
|
|
ENDSWITCH
|
|
|
|
RETURN NIL
|
|
|
|
FUNCTION uhttpd_GetField( cVar, cType )
|
|
LOCAL xVal
|
|
LOCAL nPos := hb_HPos( _Request, cVar )
|
|
|
|
IF nPos > 0 //cVar IN ::h_Request:Keys
|
|
xVal := hb_HValueAt( _Request, nPos ) //::h_Request[ cVar ]
|
|
IF Empty( xVal )
|
|
xVal := NIL
|
|
ENDIF
|
|
IF cType != NIL .AND. cType $ "NLD"
|
|
xVal := uhttpd_CStrToVal( xVal, cType )
|
|
ENDIF
|
|
ENDIF
|
|
|
|
RETURN xVal
|
|
|
|
FUNCTION uhttpd_SetField( cVar, cVal )
|
|
LOCAL xVal := uhttpd_HGetValue( _Request, cVar )
|
|
_Request[ cVar ] := cVal
|
|
RETURN xVal
|
|
|
|
FUNCTION uhttpd_HGetValue( hHash, cKey )
|
|
LOCAL nPos
|
|
LOCAL xVal
|
|
IF hHash != NIL
|
|
xVal := iif( ( nPos := hb_HPos( hHash, cKey )) == 0, NIL, hb_HValueAt( hHash, nPos) )
|
|
ENDIF
|
|
//RETURN iif( cKey IN hHash:Keys, hHash[ cKey ], NIL )
|
|
RETURN xVal
|