lastmax% PROC_debug(3,"max connections")
lastmax%=TIME+500
ENDPROC
ENDIF
!hostsize%=16
SYS "Socket_Accept", socket%, remotehost%, hostsize% TO connect%
IF connect%=-1 THEN PROC_debug(0,"Failed "):ENDPROC
PROC_fd_set(data_sel%, connect%)
cc%+=1
a$=STR$(remotehost%?4)+"."+STR$(remotehost%?5)+"."
a$+=STR$(remotehost%?6)+"."+STR$(remotehost%?7)
use_rev_dns%=TRUE
IF use_rev_dns% THEN
SYS "XInternet_GetHostByAddr",,remotehost%+4,4,2 TO ,shp%
IF shp%>0 THEN a$=FN_zero(!shp%)
ENDIF
PROC_debug(0,a$+" wants http")
FOR X%=1 TO maxknx%:IF knx%(X%)=-1 THEN
knx%(X%)=connect%:port%(X%)=port%:ptr%(X%)=0:first%(X%)=0:redir%(X%)=0:X%=maxknx%
ENDIF
NEXT
connect%=-1
ENDPROC
DEF PROC_conn_kill(x%)
break%=TRUE
IF knx%(x%) > -1 THEN
PROC_debug(3,"Closing socket "+STR$knx%(x%))
SYS "XSocket_Shutdown", knx%(x%), 2
SYS "XSocket_Close", knx%(x%)
PROC_fd_clr(data_sel%, knx%(x%))
knx%(x%)=-1
cc%-=1
ENDIF
IF file%(x%)>0 CLOSE #file%(x%):file%(x%)=-1
url$(x%)=""
ENDPROC
DEF PROC_sock_write(sock%, str$)
IF LENstr$>60 THEN
PROC_sock_write(sock%, LEFT$(str$,60))
PROC_sock_write(sock%, MID$(str$,61))
ELSE
$iobuf% = str$
SYS "XSocket_Write", sock%, iobuf%, LENstr$
ENDIF
ENDPROC
DEF PROC_resp_screen(x%,code%,id$,reason$)
LOCAL s%:s%=knx%(x%)
LOCAL ERROR
ON ERROR LOCAL ON ERROR LOCAL OFF:ENDPROC
PROC_sock_write(s%, "HTTP/1.0 "+STR$code%+" "+id$+nl$+"MIME-version: 1.0"+nl$)
PROC_sock_write(s%, server$+nl$)
PROC_sock_write(s%, "Content-type: text/html"+nl$+nl$)
PROC_sock_write(s%, ""+STR$code%+" "+id$+""+nl$)
PROC_sock_write(s%, ""+STR$code%+" "+id$+"
"+nl$+reason$)
IF code%=302 ENDPROC
PROC_sock_write(s%, ""+nl$+"
"+nl$+sig$+""+nl$)
ENDPROC
DEF PROC_redirect(x%)
PROC_debug(0,"302 Relocate for "+url$(x%))
PROC_resp_screen(x%, 302, "Not here", "The requested document is no longer at this URL")
PROC_sock_write(s%, "It has moved to another location
"+nl$)
PROC_sock_write(s%, sig$+nl$)
PROC_conn_kill(x%)
ENDPROC
DEF PROC_not_found(x%)
PROC_debug(0,"404 Not found for "+url$(x%))
PROC_resp_screen(x%,404,"Not found","The request URL was not found on this server")
PROC_conn_kill(x%)
ENDPROC
DEF PROC_bad_request(x%)
PROC_debug(0,"400 Bad access method")
PROC_resp_screen(x%, 400, "Bad request", "Your client sent a query that the server could not understand")
PROC_conn_kill(x%)
ENDPROC
DEF PROC_retrieve_url(x%, full%)
PROC_debug(0,"200 OK for "+url$(x%))
LOCAL ERROR
ON ERROR LOCAL ON ERROR LOCAL OFF:ENDPROC
file%(x%)=OPENIN file$(x%)
IF file%(x%)=0 THEN PROC_not_found(x%):PROC_conn_kill(x%):ENDPROC
SYS "OS_Args",2,file%(x%) TO ,,ext%(x%)
ptr%(x%)=0
len%(x%)=0
IF mime$(x%)="" THEN
PROC_debug(0,"Executing CGI script "+url$(x%))
CLOSE #file%(x%)
file%(x%)=-1
tmp$="http/1.0":IF NOT full% tmp$="http/0.9"
SYS "Wimp_StartTask", file$(x%)+" "+tmp$+" -socket "+STR$knx%(x%)
break%=TRUE
cc%-=1
knx%(x%)=-1
url$(x%)=""
ELSE
IF NOT full% THEN ENDPROC
PROC_sock_write(knx%(x%), "HTTP/1.0 200 OK" + nl$)
PROC_sock_write(knx%(x%), server$+nl$)
PROC_sock_write(knx%(x%), "MIME-version: 1.0"+nl$)
PROC_sock_write(knx%(x%), "Content-Type: " +mime$(x%)+ nl$)
PROC_sock_write(knx%(x%), "Content-Length: "+STR$ext%(x%)+nl$)
PROC_sock_write(knx%(x%), rocont$(x%)+nl$)
PROC_sock_write(knx%(x%), nl$)
ENDIF
ENDPROC
DEF PROC_do_o(x%)
IF len%(x%)=0 THEN
SYS "OS_GBPB", 4, file%(x%), io%(x%), bufsiz% TO ,,,unread%
len%(x%) = bufsiz%-unread%: IF unread%=bufsiz% THEN PROC_conn_kill(x%):ENDPROC
ENDIF
SYS "XSocket_Write", knx%(x%), io%(x%), len%(x%)
len%(x%)=0
ENDPROC
DEF PROC_io_filbuf(fdset%)
LOCAL x%
FOR x%=1 TO maxknx%
IF FN_fd_isset(fdset%,knx%(x%)) PROC_do_o(x%)
NEXT
ENDPROC
DEF FN_xlate(p$)
LOCAL p%,q$:q$="":FOR p%=1 TO LENp$
CASE MID$(p$,p%,1) OF
WHEN "/": q$+="."
WHEN ".": q$+="/"
WHEN ":","$","%","&", "^", "*", """", "@", "#", "<", ">": =""
OTHERWISE: q$+=MID$(p$,p%,1)
ENDCASE
NEXT
=q$
DEF PROC_lookup(x%,p$)
LOCAL was_cgi%
IF LEFT$(p$,1) <> "/" p$="/"+p$
was_cgi% = (FN_lower((LEFT$(p$,9))) = "/cgi-bin/")
p$=FN_xlate(p$)
IF p$="" THEN PROC_not_found(x%):PROC_conn_kill(x%):ENDPROC
IF RIGHT$(p$,1) = ".": p$+="index/html"
file$(x%)=lib$+LEFT$(p$,255-LENlib$)
SYS "OS_File", 23, file$(x%) TO obj%,,,,,,type%
PROC_debug(2,file$(x%)+" "+STR$obj%+" "+STR$~type%)
IF obj%=3 obj%=1
IF obj%=2 OR obj%=3 file$(x%)+=".index/html":SYS "OS_File", 23, file$(x%) TO obj%,,,,,,type%
IF obj%<>1 THEN PROC_not_found(x%):PROC_conn_kill(x%):ENDPROC
IF was_cgi% THEN mime$(x%)="":ENDPROC
rocont$(x%)="X-RiscOS-Filetype: "+STR$~type%
CASE type% OF
WHEN &FAF,&345: mime$(x%)="text/html"
WHEN &FFF: mime$(x%)="text/plain"
WHEN &695: mime$(x%)="image/gif"
WHEN &C85: mime$(x%)="image/jpeg"
WHEN &AE7: mime$(x%)="video/armovie"
WHEN &BF8: mime$(x%)="video/mpeg"
WHEN &FF8,&FFB: mime$(x%)="application/octet-stream"
WHEN &DDC: mime$(x%)="application/x-sparkive"
WHEN &3FB, &1000, &2000: mime$(x%)="application/x-arcfs"
OTHERWISE: PROC_not_found(x%): PROC_conn_kill(x%)
ENDCASE
ENDPROC
DEF PROC_authorise(x%,p$)
IF LEFT$(p$,LENroot_pw$) <> root_pw$ THEN PROC_debug(0,"ROOT authentication failed"):ENDPROC
mime$(x%)="application/octet-stream"
file$(x%)=MID$(p$,2+LENroot_pw$)
PROC_debug(0,"ROOT authorisation for "+file$(x%))
ENDPROC
DEF PROC_io(y%)
LOCAL x%,p%,flag%
LOCAL ERROR: ON ERROR LOCAL OFF: PROC_conn_kill(x%):break%=TRUE:PROC_debug(0,REPORT$+" "+STR$ERL):ENDPROC
FOR x%=1 TO maxknx%
IF FN_fd_isset(y%,knx%(x%)) THEN
SYS "XSocket_Read",knx%(x%),iobuf%,1 TO bytes_read%;flag%
IF (flag%AND1)=1 THEN PROC_conn_kill(x%):PROC_debug(0,REPORT$):break%=TRUE:ENDPROC
IF (bytes_read%=0 AND first%(x%) < 2) THEN
bytes_read%=1
?iobuf%=10
ENDIF
CASE bytes_read% OF
WHEN -1:
PROC_debug(0,"exceptional condition on socket (read failed) closing")
PROC_conn_kill(x%)
WHEN 0:
PROC_debug(0,"no more input on socket")
PROC_conn_kill(x%)
OTHERWISE:
IF (first%(x%)>1):NEXT:ENDPROC
c%=?iobuf%
ptr%(x%)?io%(x%)=c%
IF (c% = 10) THEN
IF first%(x%)=1 THEN
p%=0
p$="":WHILE LENp$<254 AND p% "GET ":PROC_bad_request(x%):PROC_debug(0,"HDR:"+p$):ENDPROC
p$="":WHILE LENp$<254 AND p%?io%(x%) <> 10 AND p%?io%(x%)<>13
p$+=CHR$(p%?io%(x%)):p%+=1
ENDWHILE
IF (p%?io%(x%) <> 10 AND p%?io%(x%) <> 13) THEN
PROC_not_found(x%):PROC_conn_kill(x%):NEXT:ENDPROC
ENDIF
IF RIGHT$(p$,8)="HTTP/1.0" THEN p$=LEFT$(p$,LENp$-9):full%=TRUE:ELSE:full%=FALSE
url$(x%)=p$
PROC_debug(3,"requested "+p$)
PROC_lookup(x%, p$)
IF (knx%(x%)>-1) AND NOT full% THEN
first%(x%)=2:PROC_retrieve_url(x%, FALSE)
ENDIF
ELSE
IF (ptr%(x%)=0 OR (ptr%(x%)=1 AND ?io%(x%)=13)) AND first%(x%) = 1 THEN
PROC_debug(3,"Finished reading headers - sending")
first%(x%)=2
IF redir%(x%)=0 THEN PROC_retrieve_url(x%,TRUE) ELSE PROC_redirect(x%)
ENDIF
REM Ignore other headers for now
ENDIF
ptr%(x%) = 0
ELSE
ptr%(x%)+=1
ENDIF
ENDCASE
ENDIF
NEXT
ENDPROC
DEF PROC_validate_all_sockets
LOCAL K%,x%
FOR x%=1 TO maxknx%
IF knx%(x%) > -1 THEN
timeout%!4=16
SYS "XSocket_Getsockname",knx%(x%), valid_sel%, timeout%+4 TO ;K%
IF (K%AND1)=1 THEN
PROC_conn_kill(x%)
PROC_debug(0,"validate: killing socket")
ENDIF
ENDIF
NEXT
ENDPROC
DEF PROC_select
LOCAL word%,byte%,bit%,y%,choice%,lo%
LOCAL ERROR
ON ERROR LOCAL ON ERROR LOCAL OFF:PROC_debug(0,REPORT$+" "+STR$ERL):ENDPROC
del%=20
break%=FALSE
IF socket%=-1 THEN end%=TRUE:ENDPROC
!timeout%=0:timeout%!4=0
PROC_fd_copy(connect_sel%,valid_sel%)
SYS "XSocket_Select",256,valid_sel%,0,0,timeout% TO choice%;y%
IF (y%AND1)=1 THEN end%=TRUE:ENDPROC:REM Serious error on control socket
IF choice%>0 THEN PROC_accept
PROC_fd_copy(data_sel%, select_excep%)
!timeout%=0:timeout%!4=0
SYS "XSocket_Select",256,0,0,select_excep%,timeout% TO choice%;y%
IF (y%AND1)=1 THEN PROC_validate_all_sockets:ENDPROC
IF choice%>0 THEN PROC_io(select_excep%)
FOR lo%=1 TO 100
!timeout%=0:timeout%!4=0
PROC_fd_copy(data_sel%, select_read%)
SYS "XSocket_Select",256,select_read%,0,0,timeout% TO choice%;y%
IF (y%AND1)=1 THEN
PROC_validate_all_sockets:ENDPROC
ENDIF
IF choice%>0 THEN
PROC_io(select_read%):del%=0
ELSE
lo%=100
ENDIF
NEXT
:
!timeout%=0:timeout%!4=0
PROC_fd_copy(data_sel%, select_write%)
FOR y%=1 TO maxknx%
IF NOT (knx%(y%)>-1 AND first%(y%)>1) PROC_fd_clr(select_write%, knx%(y%))
NEXT
SYS "XSocket_Select",256,0,select_write%,0,timeout% TO choice%;y%
IF (y%AND1)=0 AND choice%>0 THEN PROC_io_filbuf(select_write%):del%=0
ENDPROC
DEF PROC_htons(address%,value%)
address%?0 = (value% DIV 256)
address%?1 = (value% MOD 256)
ENDPROC
DEF PROC_init
LOCAL ERROR:ON ERROR LOCAL OFF:PROC_debug(0,STR$ERR+" "+REPORT$):ENDPROC
AF_INET% = 2: SOCK_STREAM% = 1
DIM address% 16
SYS "Socket_Creat", AF_INET%, SOCK_STREAM%, 0 TO socket%
IF socket%<0 OR socket%>31 ERROR EXT 0,"Unable to Create Socket"
!address%=2
PROC_htons(address%+2,port%)
address%!4 = 0 :address%!8 = 0: address%!12 = 0
SYS "Socket_Bind", socket%, address%, 16
SYS "Socket_Listen", socket%, 5
PROC_fd_zero(connect_sel%)
PROC_fd_set(connect_sel%,socket%)
PROC_fd_zero(data_sel%)
PROC_debug(0,"starting")
FOR X%=1 TO maxknx%
DIM mem% bufsiz%
io%(X%)=mem%
NEXT
ENDPROC
DEF PROC_exit
IF socket% <> -1: SYS "XSocket_Shutdown",socket%,2:SYS "XSocket_Close", socket%
IF connect% <> -1:SYS "XSocket_Shutdown",connect%,2:SYS "XSocket_Close", connect%
FOR x%=1 TO maxknx%
IF knx%(x%)>=0 PROC_conn_kill(x%)
NEXT
ENDPROC
DEF PROC_errstop
ON ERROR OFF:PROC_debug(0,REPORT$+" ("+STR$ERL+")")
PROC_exit
END
ENDPROC
DEF PROC_debug(lev%,x$)
LOCAL ERROR:ON ERROR LOCAL OFF:ENDPROC
SYS "XInternet_Syslog","httpd",x$,lev%
ENDPROC