REM >httpServer END=1024*128: REM 96K WimpSlot REM Change this to be your authorisation keyword REM If you want a secure server, leave it as empty string root_pw$="" REM Change this line to the root of your web pages lib$="ADFS::HardDisc5.$.Internet.WWWPages" end%=FALSE:socket%=-1:connect%=-1:cc%=0:maxknx%=4 lastmax%=TIME bufsiz%=1024 port%=80 nl$=CHR$10 task$="HTTP Server ("+STR$port%+")" server$="Server: RISCOS/3.5 httpserver/0.8beta" sig$="RISC OS httpd 0.8 (Acorn RiscPC600 25MB) (S.N.Brodie)" DIM taskid%8,q%&100,select_read%32,select_write%32,select_excep%32,timeout%8 DIM iobuf%64,remotehost%16,hostsize%4,valid_sel%32,connect_sel%32 DIM data_sel%32 DIM knx%(maxknx%),port%(maxknx%),io%(maxknx%),ptr%(maxknx%),first%(maxknx%),url$(maxknx%) DIM file%(maxknx%),ext%(maxknx%),len%(maxknx%),file$(maxknx%),mime$(maxknx%),redir%(maxknx%) DIM rocont$(maxknx%) url$() = STRING$(254," "):url$() = "": REM Reserve memory NOW file$() = STRING$(254," "):file$() = "": REM Ditto mime$() = "application/octet-stream": mime$() = "": REM Ditto rocont$() = "X-RiscOS-Filetype: xxx " redir%() = 0 ptr%()=0 knx%()=-1 file%()=-1 ON ERROR:PROC_errstop:END PROC_init $taskid%="TASK" SYS "Wimp_Initialise", 310, !taskid%, task$, -1 TO ,task_id% del%=0 WHILE NOT end% SYS "Wimp_PollIdle",,q%,FN_timenow+del% TO reason% CASE reason% OF WHEN 1: SYS "Wimp_RedrawWindow",,q% TO more% WHILE more%:SYS "Wimp_GetRectange",,q% TO more%:ENDWHILE WHEN 2: SYS "Wimp_OpenWindow",,q% WHEN 3: SYS "Wimp_CloseWindow",,q% WHEN 17,18: PROC_message OTHERWISE: PROC_select ENDCASE ENDWHILE PROC_exit END DEF FN_lower(A$):LOCALB$,B%,C%:B$="":FORB%=1 TO LENA$:C%=ASCMID$(A$,B%) IFC%>=65 AND C%<=90 C%+=32 B$+=CHR$C%:NEXT:=B$ DEF FN_timenow:LOCALA%:SYS "OS_ReadMonotonicTime" TO A%:=A% DEF FN_task_same y$="":y%=q%+28:WHILE (?y%) >=32:y$+=CHR$(?y%):y%+=1:ENDWHILE =(y$=task$) DEF FN_zero(ptr%):LOCAL A$:A$="" WHILELENA$<255 AND ?ptr%:A$+=CHR$(?ptr%):ptr%+=1:ENDWHILE =A$ DEF PROC_message IF q%!16 = 0 THEN end%=TRUE IF q%!16 = &400C2 AND FN_task_same AND q%!4 <> task_id% THEN end%=TRUE ENDPROC DEF PROC_fd_zero(base%) LOCAL T%:FORT%=0 TO 28 STEP 4:base%!T%=0:NEXT ENDPROC DEF PROC_fd_copy(base%,dest%) LOCAL T%:FORT%=0 TO 28 STEP 4:dest%!T%=base%!T%:NEXT ENDPROC DEF PROC_fd_set(base%, fd%) IF fd%<0 OR fd%>255 THEN ENDPROC WHILE fd%>=8 :base%+=1:fd%-=8:ENDWHILE ?base%=(?base% OR (1<255 THEN ENDPROC WHILE fd%>=8 :base%+=1:fd%-=8:ENDWHILE ?base%=(?base% AND NOT (1<255 THEN =FALSE WHILE fd%>=8:base%+=1:fd%-=8:ENDWHILE IF ((?base%) AND (1<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