~digi/tclwebserver

551d1d7291d20ec41afda2a3b7cea543c083f8c3 — dibitol 1 year, 1 month ago
init
6 files changed, 168 insertions(+), 0 deletions(-)

A access.log
A readme.txt
A server.tcl
A views/404.html
A views/dir.html
A views/file.html
A  => access.log +0 -0
A  => readme.txt +16 -0
@@ 1,16 @@
25.11.2020
----------

simple http server written in Tcl just for experimental purposes.
it doesn't have any advantages over thttpd or darkhttpd (i highly recommend this to use).
nearly 100 lines

features
-html serve (wow)
-route designing
-directory viewing
-404 page
-access logging

TODO (maybe)
-image and other mime types support
\ No newline at end of file

A  => server.tcl +107 -0
@@ 1,107 @@
# simple web server attempt
# 18.11.2020
# with tcl 8.6.9

# this is main root holder
# when something is read on server, ::route changes
set ::route ""
set ::okHeader {
	HTTP/1.1 200 OK
	Content-Type: text/html; charset=UTF-8\r\n\r\n
}
proc ::svStart {channel addr port} {
    # this is for async socket read
	fconfigure $channel -blocking 0
	set logFile [open "access.log" "a+"]
    # logging accesses
	puts $logFile "[fconfigure $channel -sockname] /$::route"
	close $logFile
	::svRead $channel
	::svWrite $channel
}
proc ::svRead {channel} {
	set input [gets $channel]
    # if you really want an icon you can change this
	if [string match "*favicon*" $input] {
		return 0
    # parsing request
	} elseif [string match "GET /* HTTP/1.1" $input] {
		regexp "/(.*) HTTP/1.1" $input temp ::route
	}
}
proc ::svWrite {channel} {
	puts $channel $::okHeader
    # index route "/"
	if {$::route eq ""} {
		set st [::returnDir]
		puts $channel $st
    # for directories
    # in directories i didn't want to show folders
    # glob -type f(ile) means that
	} elseif [string match "*/" $::route] {
		set st [::returnDir $::route]
		puts $channel $st
    # for returning file
    # just for text files
    # it doesn't read image or etc.  
	} elseif [string match "*\.*" $::route] {
		set st [::returnFile $::route]
		puts $channel $st
    # if requested route is in user generated ::paths
    # it returns it
    # if it isn't there
    # returns 404
	} else {
		if [info exists ::paths($::route)] {
			puts $channel $::paths($::route)
		} else {
			puts $channel $::fourofour
		} 
	}
    # you know we always need to flush
	flush $channel
	after 2000 [list close $channel]
}
proc ::returnDir {{dir ""}} {
    # for memoizing index.html 
    # we need to call twice
	set index [format "%sindex.html" $dir]
	if {[glob -nocomplain "$dir*"] eq ""} {
		return $::fourofour
	} elseif {[glob -nocomplain $index] ne ""} {
		set indexFile [open $index "r"]
		return [read $indexFile]
	}
    # little template engine here
    # it's quite pathetic and hard to read
	set pContent [string map [list {#dizin#} $dir {#dosyalar#} "[join [lmap ex [glob -type f "$dir*"] {format {<a href='/%s'>%s</a><br>} $ex $ex}] " "]"] $::dirContent]
	return $pContent
}
proc ::readFile {path} {
    # just for html files
    # it doesn't read binary
	set temp [open "$path" "r"]
	return [read $temp]
}
proc ::returnFile {file} {
    if [file exists $file] {
	   set file [open "$file" "rb"]
	   return [string map [list {#ic#} [read $file]] $::fileContent]
    } else {
        return $::fourofour
    }
}
proc ::main {{port 80}} {
	set skt [socket -server ::svStart $port]
	vwait forever
}
# those three are necessary
# if you want to add
# just change ::paths array
set ::dirContent [::readFile "views/dir.html"]
set ::fourofour [::readFile "views/404.html"]
set ::fileContent [::readFile "views/file.html"]
array set ::paths {}

# here we go again
::main 80
\ No newline at end of file

A  => views/404.html +16 -0
@@ 1,16 @@
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>404</title>
</head>
<body>
<h1>Kardeşim sen hele nerelerde gezersin öyle</h1>
<p>Hele Geri Dön Sen</p>
<hr>
<i>Tsv<br>
Kaynak kodlarını bulabilirsiniz
</i>
</body>
</html>
\ No newline at end of file

A  => views/dir.html +13 -0
@@ 1,13 @@
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>#dizin#</title>
</head>
	<body>
	<p style="font-family:monospace;">
	#dosyalar#
	</p>
</body>
</html>
\ No newline at end of file

A  => views/file.html +16 -0
@@ 1,16 @@
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
	</head>
	<body>
		<pre>
#ic#		
		</pre>
		<hr>
	<i>Tsv<br>
	Kaynak kodlarını bulabilirsiniz
	</i>
	</body>
</html>