MiniWebServer

BlitzMax Forums/BlitzMax Programming/MiniWebServer

skidracer(Posted 2006) [#1]
This is a mini webserver I am hoping to run online sometime.

Run the following in the same folder as an index.html file and then launch a webbrowser to localhost:4663 which is the same port as googledesktop but they don't seem to mind each other.

I'm going to start compiling BlitzMax CGI programs on my remote account first which is another topic but would like to keep developing the following so if anyone wants to help, I need some sort of session manager code that looks after cookies etc.

I'll probably look at support for standard CGI-bin process launching next.

A web front end for the miniwebserver user interface would also be good, perhaps it could listen on another port and allow you to do session control stuff from the browser, sync files, show stats etc.

' minwebserver.bmx

Strict

Local socket:TSocket=CreateTCPSocket()
BindSocket socket,4663
SocketListen socket
Print "listening on port 4663"

While True
	Local client:TSocket=SocketAccept(socket,20)
	If client New TConnection.Create(client)
	TConnection.PollAll
'	Print "poll"
Wend

End

Type TConnection

	Global connections:TList=New TList

	Field id
	Field _socket:TSocket
	Field _stream:TStream
	Field _data$
	
	Method getline$()
		Local p,l$
		p=_data.find("~n")
		If p=-1 p=_data.length
		l=_data[..p]
		_data=_data[p+1..]		
		Return l
	End Method
	
'	Method WritePage()

	Method ServePage(uri$)
		Local file$,size,p

		Print "serving "+uri+" from connection#"+id
		
		If uri$="/" 
			file="index.html"
		Else
			file=uri
			If file[..1]="/" file=file[1..]
			p=file.find("?")
			If p>0 file=file[..p]
'			file=uri[..p]
'			uri=args[p..]
		EndIf

		If file And FileType(file)=FILETYPE_FILE
			size=FileSize(file)
			If size=0
				Print "ServePage "+uri+" is empty"
				Return
			EndIf			
			WriteLine _stream,"HTTP/1.1 200 OK"
			WriteLine _stream,"Content-Type: text/html; charset=UTF-8"
			WriteLine _stream,"Content-Length: "+size
			WriteLine _stream,"Pragma: no-cache"
			WriteLine _stream,"Expires: Fri, 01 Jan 1990 00:00:00 GMT"
			WriteLine _stream,"Cache-control: no-cache, no-store, must-revalidate"
			WriteLine _stream,"Connection: keep-alive"
			WriteLine _stream,"Keep-Alive: 30000"
			WriteLine _stream,""
			WriteLine _stream,LoadText(file)					
'			DebugLog file+" sent"
		Else
			DebugLog "Failed To find file "+file
		EndIf		
'		debuglog "Served!"
	End Method
	
	Field getname$
	
	Method Poll()
		Local bytes,mess$
		bytes=SocketReadAvail(_socket)
		If bytes
			_data:+ReadString(_stream,bytes)
		EndIf
		While _data
			mess=Trim(getline())
'			Print "*"+mess
			If mess[..4]="GET "
				getname=mess[4..]
				getname=getname.replace(" HTTP/1.1","")
			EndIf			
			If mess=""
				If getname
					ServePage getname
					getname=""
				Else
					Print "blank line unknown!"
				EndIf
			Else
				'If getname="" Print "$"+mess+"$"
				'Print mess
			EndIf
		Wend	
	End Method
	
	Method Create:TConnection(client:TSocket)
		Print "creating connection!"
		_socket=client
		_stream=CreateSocketStream(client)
		connections.AddLast Self
		id=connections.count()
		Return Self
	End Method

	Function PollAll()
		Local connect:TConnection
		For connect=EachIn connections
			connect.Poll
		Next
	End Function		
End Type



Matthew Smith(Posted 2006) [#2]
Hey skid - works really well on the local.

Should this work across a local network? Tried accessing from another PC, the server advises 'serving / HTTP/1.0 from connection#1, but the PC is stuck on opening page.

This is on my work network (which could be locked down somewhere), I'll give it a try on our testlab network shortly.


Michael Reitzenstein(Posted 2006) [#3]
You crazy.


FlameDuck(Posted 2006) [#4]
What Michael said. A non-threaded webserver simply doesn't have the performace to be generally useful. Use Lighttpd instead.


Winni(Posted 2006) [#5]
Hmmm... If that statement about multithreading would be true, then I wonder how the old Unix servers were able to deliver in the times when Unix (including Linux) did not support multithreading? Were they spawning new processes for every new connection?


FlameDuck(Posted 2006) [#6]
I wonder how the old Unix servers were able to deliver in the times when Unix (including Linux) did not support multithreading?
Pre-1970's Unix systems where not operated as servers.


Winni(Posted 2006) [#7]
But you do know that Linux only in 1998+/- began to have multithreading support? Until then, it only had multitasking capabilities, but was very well used as a server.

And what about sendmail? If I am not mistaken, it also is not multithreaded. Postfix is, but not sendmail. Neither are some of the older Usenet NNTP servers, e.g.

I think my original question is valid: If you don't have multitasking, how do you write a working server? Obviously, it -is- possible. And must be - after all sooner or later things must be serialized, and if it's just for the hardware access.


ozak(Posted 2006) [#8]
Actually it works just as well by asking connections if they have any data.
Multithreading usually occurs controlled on servers (thread pool) since just spawning a process for each connection can easily kill the server :)


Winni(Posted 2006) [#9]
Yes, it would be quite easy to bring a server to its knees with that approach. :)

Well, I'll go on with the SocketReadAvai() approach then.


Blitzplotter(Posted 2006) [#10]
Skidserver worked well here, received the following results:

Building skidserver
Compiling:skidserver.bmx
flat assembler version 1.66
3 passes, 7408 bytes.
Linking:skidserver.exe
Executing:skidserver.exe
listening on port 4663
creating connection!
serving / from connection#1

I'm off to analyse the code now to see what I can learn from it - being a noob to server-ing in BMax....


FlameDuck(Posted 2006) [#11]
If you don't have multitasking, how do you write a working server?
If you're using a proper OS, use Inetd. Which would probably be the prefered solution in this case aswell, so you don't have to do all the socket handling but can just use stdio.


Winni(Posted 2006) [#12]
Thanks, FlameDuck, that opens a new perspective. On OS X, this now would be xinetd instead of inetd, if I'm not wrong. I guess I'll take a closer look at this. :)


Winni(Posted 2006) [#13]
Oh, I'm now reading that on Tiger, launchd also replaced xinetd. They seem to change things rather quicky. :)


Perturbatio(Posted 2006) [#14]
on the security side, you can download the server app by specifying it's name.

*EDIT*
forgot to add...

cool :)

I might tinker with this if I can get some time (at christmas maybe).