Code archives/Networking/BlitzServe

This code has been declared by its author to be Public Domain code.

Download source code

BlitzServe by BlitzSupport2003
This is an update to the previous code I placed in the Code Archives. It now serves files... :)

There are tons of limitations, and it would need loads of things added to be useable as a real server, but it might give someone an idea of how to handle this sorta thing...

There's a hell of a lot of work required to make a HTTP server work 'properly' -- see http://www.w3.org/Protocols/rfc2616/rfc2616.html for HTTP 1.1 definition!

UPDATED: Just fixed to convert all '%20' style characters in URLs (eg. %20 = a space).
; -----------------------------------------------------------------------------
; BlitzServe: a very crude HTTP server...
; -----------------------------------------------------------------------------
; james @ hi - toro . com
; -----------------------------------------------------------------------------

; Although this can accept unlimited connections, it'll only actually serve one
; file at a time because I can't launch the file-send part of the code as a
; separate thread, meaning the program flow is held up while a file is being
; sent. Also, for reasons unknown, sending a file to a browser on the same
; machine is VERY slow, though it's nice and quick over a network...

AppTitle "BlitzServe..."

; -----------------------------------------------------------------------------
; The place you'll put any files to be served. It's like an FTP directory...
; -----------------------------------------------------------------------------

folder$ = "C:\My Documents"

; Just stripping any "/" characters you or I might accidentally stick on the end ;)

If (Right (folder$, 1) = "/") Or (Right (folder$, 1) = "\")	
	folder$ = Left (folder$, Len (folder$) - 1)
EndIf

; -----------------------------------------------------------------------------
; To test, open Internet Explorer and type http://127.0.0.1/whatever/
; -----------------------------------------------------------------------------
; For example, if you have a file called hotpr0n.html in the above folder,
; you'd type 127.0.0.1/hotpr0n.html into your browser...
; -----------------------------------------------------------------------------

; (Note: 127.0.0.1 is always the local PC. If you're on a network, you can run
; IE on another PC and replace 127.0.0.1 with the actual IP address of the
; PC this server is running on.)

; -----------------------------------------------------------------------------
; Connection list type...
; -----------------------------------------------------------------------------

Type Connection
	Field number ; Stream identifier
	Field stream ; Stream handle
End Type

; -----------------------------------------------------------------------------
; Create HTTP server (always on port 80)...
; -----------------------------------------------------------------------------

server = CreateTCPServer (80)

If server

	Print
	Print "BlitzServe: awaiting incoming connections..."
	Print
	
	Repeat
	
		; -------------------------------------------------------------------------
		; See if there's been an incoming connection attempt...
		; -------------------------------------------------------------------------
	
		tstream = AcceptTCPStream (server)
	
		If tstream
	
			; ---------------------------------------------------------------------
			; Got one? OK, create a new Connection entry...
			; ---------------------------------------------------------------------
	
			Print
			Print "Got new connection..."
			Print
			
			c.Connection = New Connection
			c\number = count
			c\stream = tstream
			
			; ---------------------------------------------------------------------
			; A HTTP request end with a blank line, so we read until we get that...
			; ---------------------------------------------------------------------
	
			Repeat
			
				; -----------------------------------------------------------------
				; Read a line from an incoming HTTP request...
				; -----------------------------------------------------------------

				; The format of an incoming request line is:
				
				;		"Command" [space] "parameters"

				; Examples...
								
				;		"GET /thisfile.txt"
				;		"User-Agent: AcmeBrowse"
				
				incoming$ = ReadLine (c\stream)

;				DebugLog "Stream " + c\number + ": " + incoming$

				If incoming$ <> ""

					; -------------------------------------------------------------
					; Got a line? Let's parse! Split command and parameter(s)...
					; -------------------------------------------------------------

					eoc = Instr (incoming$, " ")				; End of command part of incoming$
					command$ = Lower (Left (incoming$, eoc))	; Command part of incoming$
					parameter$ = Mid (incoming$, eoc + 1)		; Parameter part of incoming$

				EndIf
					
				; -----------------------------------------------------------------
				; Let's see what command we've got...
				; -----------------------------------------------------------------

				Select command$
				
					Case "get "

						; ---------------------------------------------------------
						; Got a HTTP file request!
						; ---------------------------------------------------------

						; Format of GET is: "GET /thisfile.txt"
						
						eop = Instr (parameter$, " ")			; End of first parameter ("GET")
						file$ = Mid (parameter$, 1, eop - 1)	; First parameter ("GET")
						http$ = Mid (parameter$, eop + 1)		; Second parameter ("/thisfile.txt")

						; ---------------------------------------------------------
						; Requesting program's name/identifier...
						; ---------------------------------------------------------

					Case "user-agent: "
						program$ = Mid (incoming$, eoc + 1)
						
				End Select
				
			Until incoming$ = "" ; Got blank line after headers, all done here...

			; ---------------------------------------------------------------------
			; Lessee what we've got...
			; ---------------------------------------------------------------------
			
			Print "Requested file: " + file$
			Print "Requested by: " + program$
			Print "Requested HTTP version: " + http$

			; ---------------------------------------------------------------------
			; 'K, we barely know what we're doing as it is, so only HTTP 1.1...
			; ---------------------------------------------------------------------
			
			If http$ <> "HTTP/1.1"

				WriteLine c\stream, "HTTP/1.1 505 This server only accepts HTTP version 1.1"
				WriteLine c\stream, ""
				CloseTCPStream c\stream: Delete c

			Else
			
				; -----------------------------------------------------------------
				; It was a HTTP 1.1 request...
				; -----------------------------------------------------------------

				If file$ <> ""

					; Convert any %xx (hex) codes in URL to Chr (ascii) character...
					; (Eg. %20 is ascii 57, ie. Chr (57), ie. a Space.)
					
					file$ = UnHexURL (file$)

					Print
					Print "Attempting to send " + file$ + "..."
					Print
					
					If Left (file$, 1) <> "/"
						file$ = "/" + file$ ; Strip leading "/" if any...
					EndIf

					; -------------------------------------------------------------
					; Does the requested file exist in our 'site' folder?
					; -------------------------------------------------------------

					Select FileType (folder$ + file$)
					
						Case 0 ; File does not exist...
						
							WriteLine c\stream, "HTTP/1.1 404 Not found"
							WriteLine c\stream, ""
							
							; -----------------------------------------------------
							; Close the stream and free the Connection...
							; -----------------------------------------------------
							
							CloseTCPStream c\stream
							Delete c
							
						Case 1 ; File exists!
						
							Print "Writing file..."
							Print
							
							; -----------------------------------------------------
							; Send the file. This part sucks.
							; -----------------------------------------------------

							; It's slow and needs to be performed as a separate thread,
							; since it holds program flow up! We also don't reply with a
							; polite HTTP response...

							writing = ReadFile (folder$ + file$)
							If writing
								While Not Eof (writing)
									WriteByte c\stream, ReadByte (writing)
								Wend
								Print "Sent!"
								Print
								CloseFile writing
								WriteLine c\stream, ""
							
								; -------------------------------------------------
								; Close the stream and free the Connection...
								; -------------------------------------------------
								
								CloseTCPStream c\stream
								Delete c

							EndIf
							
						Case 2 ; Folder...
						
							WriteLine c\stream, "That's a folder, dummy..."
							WriteLine c\stream, ""
							
							; -----------------------------------------------------
							; Close the stream and free the Connection...
							; -----------------------------------------------------
							
							CloseTCPStream c\stream
							Delete c
	
					End Select
					
				EndIf

			EndIf
						
			count = count + 1 ; Just the Connection number parameter for the next Connection...
			
		EndIf
		
		; -------------------------------------------------------------------------
		; Don't wanna hog CPU...
		; -------------------------------------------------------------------------
	
		Delay 100
	
	Until KeyHit (1)
	
	; -----------------------------------------------------------------------------
	; Free any open TCP streams...
	; -----------------------------------------------------------------------------
	
	For c.Connection = Each Connection
		CloseTCPStream c\stream
		Delete c
	Next

	; -----------------------------------------------------------------------------
	; Freeze! FBI! We're shutting this server down!
	; -----------------------------------------------------------------------------
	
	CloseTCPServer server

Else

	Print "Couldn't create server! Press ENTER to exit..."
	Repeat: Delay 100: Until KeyHit (28)
	
EndIf
	
End

Function UnHexURL$ (url$)
	Repeat
		pos = Instr (url$, "%")
		If pos
			hexx$ = Mid (url$, pos, 3)
			url$ = Replace (url$, hexx$, Chr (HexToDec (hexx$)))
		EndIf
	Until pos = 0
	Return url$
End Function

; From PureBasic code by 'PB'...
; (h$ can be 0-FFFFFFF)

Function HexToDec (h$)
	If Left (h$, 1) = "%" Then h$ = Right (h$, Len (h$) - 1)
	h$ = Upper (h$)
	For r=1 To Len (h$)
		d = d Shl 4: a$ = Mid (h$, r, 1)
		If Asc (a$) > 60
			d = d + Asc (a$) - 55
		Else
			d = d + Asc (a$) - 48
		EndIf
	Next
	Return d
End Function

Comments

Ching2007
Rock on Dude.
Superb stuff , Ive managed to evolve this thing into responding to HTML forms and I'm chuffed to little mince balls, about the size of marbles.
A trillion thanks.


_332007
Can you post your update? :P

Maybe? Please :§


Code Archives Forum