implemented compression for HTTP-requested data
This commit is contained in:
@@ -25,6 +25,7 @@ set nodename "tiid"
|
||||
proc createdb {fname} {
|
||||
sqlite3 fdb $fname
|
||||
fdb eval {
|
||||
PRAGMA journal_mode=WAL;
|
||||
CREATE TABLE `msg` (`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`msgid` VARCHAR(20) NOT NULL UNIQUE,
|
||||
`timestamp` INT NOT NULL,
|
||||
@@ -256,12 +257,25 @@ proc indexpage {} {
|
||||
|
||||
# TCP logic here
|
||||
|
||||
# compression function
|
||||
proc repcompress {compfunc data} {
|
||||
if {$compfunc eq {gzip}} {
|
||||
return [zlib gzip $data -level 9]
|
||||
} else {
|
||||
return [zlib $compfunc $data 9]
|
||||
}
|
||||
}
|
||||
|
||||
# error report/reply
|
||||
proc reperror {sock ishttp errmsg} {
|
||||
proc reperror {sock ishttp errmsg compfunc} {
|
||||
set errmsg "error: $errmsg\n"
|
||||
if {$ishttp eq 1} {
|
||||
set msglen [string length $errmsg]
|
||||
set hdrs "Content-Type: text/plain;charset=utf-8\r\nContent-Length: $msglen\r\nConnection: close\r\n"
|
||||
if {$compfunc ne {none}} {
|
||||
set hdrs [string cat $hdrs "Content-Encoding: $compfunc\r\n"]
|
||||
set errmsg [repcompress $compfunc $errmsg]
|
||||
}
|
||||
puts -nonewline $sock "HTTP/1.0 400 Bad Request\r\n$hdrs\r\n$errmsg"
|
||||
} else {
|
||||
puts -nonewline $sock "$errmsg"
|
||||
@@ -270,10 +284,14 @@ proc reperror {sock ishttp errmsg} {
|
||||
}
|
||||
|
||||
# successful reply with data
|
||||
proc repdata {sock ishttp data} {
|
||||
proc repdata {sock ishttp data compfunc} {
|
||||
if {$ishttp eq 1} {
|
||||
set msglen [string length $data]
|
||||
set hdrs "Content-Type: text/plain;charset=utf-8\r\nContent-Length: $msglen\r\nConnection: close\r\n"
|
||||
if {$compfunc ne {none}} {
|
||||
set hdrs [string cat $hdrs "Content-Encoding: $compfunc\r\n"]
|
||||
set data [repcompress $compfunc $data]
|
||||
}
|
||||
puts -nonewline $sock "HTTP/1.0 200 OK\r\n$hdrs\r\n$data"
|
||||
} else {
|
||||
puts -nonewline $sock $data
|
||||
@@ -284,7 +302,7 @@ proc repdata {sock ishttp data} {
|
||||
# path router
|
||||
# it only must write to the socket, not read from it or close it
|
||||
# supported paths: /e, /m, /u/e, /u/m, /u/point, /list.txt, /blacklist.txt
|
||||
proc routepath {dbfile sock ishttp path body} {
|
||||
proc routepath {dbfile sock ishttp path body compfunc} {
|
||||
fconfigure $sock -translation binary
|
||||
set pathparts [split [string trim $path] /]
|
||||
if {[llength $pathparts] > 1} {
|
||||
@@ -309,12 +327,12 @@ proc routepath {dbfile sock ishttp path body} {
|
||||
[validecho $ename] ? $ename : [continue]
|
||||
}}]
|
||||
if {[llength $erange] > 0} { # recheck length after validation
|
||||
repdata $sock $ishttp [indexechos $dbfile $erange 1 $offset $limit]
|
||||
repdata $sock $ishttp [indexechos $dbfile $erange 1 $offset $limit] $compfunc
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
m { # validate and shape the message ID list
|
||||
@@ -322,9 +340,9 @@ proc routepath {dbfile sock ishttp path body} {
|
||||
[validmsgid $mid] ? $mid : [continue]
|
||||
}}]
|
||||
if {[llength $mrange] > 0} { # we have some valid messages
|
||||
repdata $sock $ishttp [multimsg $dbfile $mrange]
|
||||
repdata $sock $ishttp [multimsg $dbfile $mrange] $compfunc
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
point {
|
||||
@@ -349,12 +367,12 @@ proc routepath {dbfile sock ishttp path body} {
|
||||
if {$authstr ne "" && $msgbody ne ""} {
|
||||
set postres [postmsg $dbfile $authstr $msgbody]
|
||||
if [string match "msg ok*" $postres] {
|
||||
repdata $sock $ishttp $postres
|
||||
repdata $sock $ishttp $postres $compfunc
|
||||
} else {
|
||||
reperror $sock $ishttp $postres
|
||||
reperror $sock $ishttp $postres $compfunc
|
||||
}
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
push {
|
||||
@@ -369,68 +387,68 @@ proc routepath {dbfile sock ishttp path body} {
|
||||
set msgbody [decurl [dict get $params upush]]
|
||||
}
|
||||
} else {
|
||||
reperror $sock $ishttp "/u/push is only available over HTTP POST"
|
||||
reperror $sock $ishttp "/u/push is only available over HTTP POST" $compfunc
|
||||
return
|
||||
}
|
||||
if {$authstr ne "" && $msgbody ne ""} {
|
||||
set postres [postbundle $dbfile $authstr $msgbody]
|
||||
if [string match "message saved: ok*" $postres] {
|
||||
repdata $sock $ishttp $postres
|
||||
repdata $sock $ishttp $postres $compfunc
|
||||
} else {
|
||||
reperror $sock $ishttp $postres
|
||||
reperror $sock $ishttp $postres $compfunc
|
||||
}
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
default {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
e {
|
||||
if {[llength $pathparts] > 2} {
|
||||
set echoname [string trim [lindex $pathparts 2]]
|
||||
if {[validecho $echoname]} {
|
||||
repdata $sock $ishttp [indexechos $dbfile [list $echoname] 0 0 0]
|
||||
repdata $sock $ishttp [indexechos $dbfile [list $echoname] 0 0 0] $compfunc
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
m {
|
||||
if {[llength $pathparts] > 2} {
|
||||
set mid [string trim [lindex $pathparts 2]]
|
||||
if {[validmsgid $mid]} {
|
||||
repdata $sock $ishttp [singlemsg $dbfile $mid]
|
||||
repdata $sock $ishttp [singlemsg $dbfile $mid] $compfunc
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
list.txt {
|
||||
repdata $sock $ishttp [listechos $dbfile]
|
||||
repdata $sock $ishttp [listechos $dbfile] $compfunc
|
||||
}
|
||||
blacklist.txt {
|
||||
repdata $sock $ishttp [blacklisted $dbfile]
|
||||
repdata $sock $ishttp [blacklisted $dbfile] $compfunc
|
||||
}
|
||||
{} {
|
||||
repdata $sock $ishttp [indexpage]
|
||||
repdata $sock $ishttp [indexpage] $compfunc
|
||||
}
|
||||
default {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reperror $sock $ishttp "invalid request"
|
||||
reperror $sock $ishttp "invalid request" $compfunc
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,43 +458,56 @@ proc reqhandler {dbfile sock} {
|
||||
# ignore all invalid requests by closing the connection
|
||||
if {[gets $sock line] >= 0} {
|
||||
if {[string match /* $line]} { # bare TCP request (Gopher/Nex)
|
||||
routepath $dbfile $sock 0 [string trim $line] {}
|
||||
} elseif {[string match -nocase {GET /*} $line]} { # HTTP GET request
|
||||
set rparts [split [string trimleft $line]]
|
||||
if {[llength $rparts] > 1} { # valid GET request
|
||||
routepath $dbfile $sock 1 [lindex $rparts 1] {}
|
||||
}
|
||||
} elseif {[string match -nocase {POST /*} $line]} { # HTTP POST request
|
||||
set rparts [split [string trimleft $line]]
|
||||
if {[llength $rparts] > 1} { # valid POST request, read POST headers and data
|
||||
set hdrread 0
|
||||
set hdata {}
|
||||
set pdata {}
|
||||
while {$hdrread < 1} {
|
||||
if {[eof $sock] || [catch {gets $sock line}]} {
|
||||
break
|
||||
} else {
|
||||
if {$line eq ""} {
|
||||
incr hdrread
|
||||
continue
|
||||
}
|
||||
set hparts [split [string trimleft $line] :]
|
||||
if {[llength $hparts] > 1} {
|
||||
set hname [string tolower [string trimright [lindex $hparts 0]]]
|
||||
set hval [string trim [lindex $hparts 1]]
|
||||
dict set hdata $hname $hval
|
||||
}
|
||||
routepath $dbfile $sock 0 [string trim $line] {} none
|
||||
} else { # HTTP request, read headers
|
||||
set hdrread 0
|
||||
set hdata {}
|
||||
set docomp none
|
||||
while {$hdrread < 1} {
|
||||
if {[eof $sock] || [catch {gets $sock hline}]} {
|
||||
break
|
||||
} else {
|
||||
if {$hline eq ""} {
|
||||
incr hdrread
|
||||
continue
|
||||
}
|
||||
set hparts [split [string trimleft $hline] :]
|
||||
if {[llength $hparts] > 1} {
|
||||
set hname [string tolower [string trimright [lindex $hparts 0]]]
|
||||
set hval [string trim [lindex $hparts 1]]
|
||||
dict set hdata $hname $hval
|
||||
}
|
||||
}
|
||||
set readlen 0
|
||||
if {[dict exists $hdata content-length]} {
|
||||
set readlen [dict get $hdata content-length]
|
||||
}
|
||||
if {[dict exists $hdata accept-encoding]} { # detect if we can gzip the output
|
||||
set enclist [dict get $hdata accept-encoding]
|
||||
if {[string match -nocase {*gzip*} $enclist]} {
|
||||
set docomp gzip
|
||||
} elseif {[string match -nocase {*deflate*} $enclist]} {
|
||||
set docomp deflate
|
||||
} elseif {[string match -nocase {*compress*} $enclist]} {
|
||||
set docomp compress
|
||||
}
|
||||
if {$readlen > 0} { # read the data defined by content-length header
|
||||
fconfigure $sock -translation {binary lf} -buffering none
|
||||
set pdata [read $sock $readlen]
|
||||
}
|
||||
if {[string match -nocase {GET /*} $line]} { # GET request
|
||||
set rparts [split [string trimleft $line]]
|
||||
if {[llength $rparts] > 1} { # valid GET request
|
||||
routepath $dbfile $sock 1 [lindex $rparts 1] {} $docomp
|
||||
}
|
||||
} elseif {[string match -nocase {POST /*} $line]} { # POST request
|
||||
set rparts [split [string trimleft $line]]
|
||||
if {[llength $rparts] > 1} { # valid POST request, read POST headers and data
|
||||
set pdata {}
|
||||
set readlen 0
|
||||
if {[dict exists $hdata content-length]} {
|
||||
set readlen [dict get $hdata content-length]
|
||||
}
|
||||
if {$readlen > 0} { # read the data defined by content-length header
|
||||
fconfigure $sock -translation {binary lf} -buffering none
|
||||
set pdata [read $sock $readlen]
|
||||
}
|
||||
routepath $dbfile $sock 1 [lindex $rparts 1] [string trimleft $pdata] $docomp
|
||||
}
|
||||
routepath $dbfile $sock 1 [lindex $rparts 1] [string trimleft $pdata]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +203,7 @@ proc n2p_id {binmsg} {
|
||||
proc createdb {fname} {
|
||||
sqlite3 fdb $fname
|
||||
fdb eval {
|
||||
PRAGMA journal_mode=WAL;
|
||||
CREATE TABLE `msg` (`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`msgid` VARCHAR(20) NOT NULL UNIQUE,
|
||||
`timestamp` INT NOT NULL,
|
||||
|
||||
Reference in New Issue
Block a user