HTTPd — File Browser
HTTPdv1.0 / HTTPdv1.0 / HTTPd / HTTPd pages.mrc
HTTPd pages.mrc — 12.21 KB — Download this file
/*
Custom HTTPd mSL pages
Here are some useful examples and aliases for creating your own mSL pages!
TO AUTHORIZE POST BODIES:
You need to authorize POST body data with "alias httpd.post.<ALIAS NAME>" alias.
Check "httpd.page./post" for an example.
TO AUTHORIZE UPLOADS:
You need to authorize multipart/form-data with "alias httpd.upload.<ALIAS name>" alias.
Check "httpd.page./upload" for an example.
WARNING: NEVER TRUST ANYTHING THE CLIENT SENDS TO THE SERVER.
Always assume the client is trying to screw you, always check and sanitize.
*/
;$httpd.cookie(<hash table>,<cookie>) - Returns the content of the cookie or $null
alias httpd.cookie return $replacex($utfdecode($regsubex($gettok($wildtok($hget($1,Cookie:),$2 $+ =?*,1,32),2,61),/%(\w\w)/g,$chr($base(\t,16,10)))),+,$chr(32))
;$httpd.safe(<text>) - Returns HTML safe version of the input text.
alias httpd.safe return $replacex($utfdecode($1),&,&,",",',',<,<,>,>)
;$httpd.unsafe(<text>) - Returns unsafe/normal version of the input text.
alias httpd.unsafe return $replacex($utfdecode($1),&,&,",",',',<,<,>,>)
;$httpd.urldecode(<text>) - Returns plain text version of the given text.
alias httpd.urldecode return $regsubex($1,/%(\w\w)/g,$chr($base(\t,16,10)))
;$httpd.urlencode(<link>) - Returns percent encoded version of the given text.
alias httpd.urlencode return $regsubex($1,/([^-.~\w])/g,% $+ $base($asc(\t),10,16))
/*
http://127.0.0.1/mypage
Example of a simple mSL page.
*/
alias httpd.page./mypage {
;"200 OK" is the default response, so you don't necessarily need to include this line.
;This is here to point out that you can change the response code if you want.
hadd $sockname Response 200 OK
;"text/html; charset=utf-8" is the default content-type, so you don't necessarily need to include this line.
;This is here to point out that you can change the content-type if you want.
hadd $sockname Content-Type text/html; charset=utf-8
;Here's the HTML code itself.
bset -t &h -1 <!DOCTYPE html>
bset -t &h -1 <html>
bset -t &h -1 <head>
bset -t &h -1 <title>My first mSL page!</title>
bset -t &h -1 </head>
bset -t &h -1 <body>
bset -t &h -1 <h2>My first mSL page!</h2>
bset -t &h -1 <p>This is my first mSL page</p>
bset -t &h -1 </body>
bset -t &h -1 </html>
;When you've filled &h binary variable with whatever data you want, call "httpd.send" alias once.
httpd.send $sockname
;The end.
}
/*
http://127.0.0.1/ip
Example of a bit more complicated mSL page.
*/
alias httpd.page./ip {
;Check for a transparent proxy.
if ($hget($sockname,via:)) || ($hget($sockname,forwarded:)) || ($hget($sockname,x-forwarded-for:)) || ($hget($sockname,client-ip:)) set -l %ip $httpd.safe($v1)
else set -l %ip
;Start of the HTML code
bset -t &h -1 <!DOCTYPE html><html><head>
;If the client is behind a transparent proxy, form the output accordingly.
if (%ip) bset -t &h -1 $+(<title>,%ip ( $+ $sock($sockname).ip $+ ),</title></head><body><p>Your IP address is: %ip,</p><p>Your proxy's IP address is: $sock($sockname).ip,</p>)
else bset -t &h -1 $+(<title>,$sock($sockname).ip,</title></head><body><p>Your IP address is: $sock($sockname).ip,</p>)
;Client headers.
bset -t &h -1 <p>Full header:</p><table><tr><th>Item</th><th>Data</th></tr>
noop $hfind($sockname,*?:,0,w,bset -t &h -1 $+(<tr><td>,$httpd.safe($1),</td><td>,$httpd.safe($hget($sockname,$1)),</td></tr>))
bset -t &h -1 </table></body></html>
;Everything done, send it to the client.
httpd.send $sockname
}
/*
http://127.0.0.1/post
Example of POST body mSL page.
To enable POST bodies, include "alias httpd.post.<PAGE NAME HERE>" alias.
The server checks if this alias exists before proceeding with a POST request that has a body.
*/
alias httpd.post./post
alias httpd.page./post {
;Set string item value to %string variable.
set -l %string $hget($sockname,item.string)
;Start of the HTML code.
bset -t &h -1 <!DOCTYPE html><html>
bset -t &h -1 <head>
bset -t &h -1 <title>Binary tool</title>
bset -t &h -1 </head>
bset -t &h -1 </body>
bset -t &h -1 <form action="/post" method="post">
bset -t &h -1 <fieldset>
bset -t &h -1 <legend>Enter your string</legend>
bset -t &h -1 $+(<p><input type="text" name="string" autofocus autocomplete="off" value=",$httpd.safe(%string),"></p>)
bset -t &h -1 <p><input type="submit" name="type" value="BIN2ASC"> <input type="submit" name="type" value="ASC2BIN"></p>
bset -t &h -1 </fieldset>
bset -t &h -1 </form>
;Check if string exists.
if (%string != $null) {
bset -t &h -1 <fieldset>
;Check what kind of conversion should be done.
if ($hget($sockname,item.type) == bin2asc) {
bset -t &h -1 <legend>BIN2ASC</legend>
;Check if the input is valid.
if ($remove(%string,0,1)) bset -t &h -1 <p>Invalid input.</p>
else {
;Convert the binary string to ASCII.
bset -t &h -1 $+(<p>,$qt($httpd.safe(%string)) converts into:</p>)
bset -t &h -1 $+(<p>,$httpd.safe($regsubex(%string,/(.{8})/g,$chr($base(\t,2,10)))),</p>)
}
}
else {
;Convert the string to binary.
bset -t &h -1 <legend>ASC2BIN</legend>
bset -t &h -1 $+(<p>,$qt($httpd.safe(%string)) converts into:</p>)
bset -t &h -1 $+(<p>,$httpd.safe($regsubex(%string,/(.)/g,$base($asc(\t),10,2,8))),</p>)
}
bset -t &h -1 </fieldset>
}
;End of the HTML code.
bset -t &h -1 </body>
bset -t &h -1 </html>
;Everything done, send it to the client.
httpd.send $sockname
}
/*
http://127.0.0.1/upload
Example of multipart upload mSL page.
To enable multipart/form-data uploads, include "alias httpd.upload.<PAGE NAME HERE>" alias.
The server checks if this alias exists before proceeding with multipart request.
*/
alias httpd.upload./upload
alias httpd.page./upload {
;Allowed file type, separated by a comma. Note: include dot in front of the file type.
set -l %accept .mp4,.mkv,.webm,.png,.jpg,.jpeg,.gif,.mp3,.flac,.ogg
;Start of the page.
bset -t &h -1 <!DOCTYPE html><html><head><title>File upload</title></head><body>
bset -t &h -1 <form action="upload" enctype="multipart/form-data" method="post">
;Check if uploads are allowed on server side or not.
if ($hget(httpd.config,AllowMultipartFormData)) && ($istok($hget(httpd.config,AllowedHTTPMethods),POST,32)) && ($isalias(httpd.upload./upload)) {
bset -t &h -1 <fieldset>
bset -t &h -1 <legend>File upload</legend>
}
else {
bset -t &h -1 <fieldset disabled>
bset -t &h -1 <legend>File upload (feature disabled on server side)</legend>
}
;HTML file input with accepted file types.
bset -t &h -1 $+(<p><input type="file" name="file" accept=",%accept," autofocus multiple required></p>)
bset -t &h -1 <p><input type="submit" value="Upload"></p>
bset -t &h -1 $+(<p><i>You can upload up to $hget(httpd.config,MaximumMultiPartItems) file(s) totaling $bytes($hget(httpd.config,MaximumMultipartSize)).suf at once.</i></p>)
bset -t &h -1 </fieldset>
bset -t &h -1 </form>
;Check if any files were uploaded.
;httpd.uploadedfiles item contains all the hashes, separated by an empty space.
;Each has is its own item on the $sockname hash table, and a file the cache directory.
if ($hget($sockname,httpd.uploadedfiles)) {
tokenize 32 $v1
;Path to your uploads folder in the root directory.
set -l %folder $hget(httpd.config,RootDirectory) $+ uploads\
;If the uploads folder doesn't exist, create it.
if (!$isdir(%folder)) mkdir $qt(%folder)
bset -t &h -1 <fieldset>
bset -t &h -1 <legend>Upload successful</legend>
;Go through each of the hashes in httpd.uploadedfiles.
while ($1) {
;Original filename in sanitized form, but the length has not been checked.
;Eg. My "upload" file.exe --> My__upload__file.exe
set -l %filename $gettok($hget($sockname,$1),1,32)
;Make sure the filename is not over 100 characters long.
;Must have enough room for the path and possible SHA1 hash.
if ($len(%filename) > 100) %filename = $+($left(%filename,90),.,$left($gettok(%filename,-1,46),9))
;Checking if the file type is in the accepted file type list.
if ($istok(%accept,. $+ $gettok(%filename,-1,46),44)) {
;Full path to the file, including quotation marks.
;Note: this fill will be deleted by the server when your page script finishes.
set -l %tempfile $gettok($hget($sockname,$1),2-,32)
;Checking if %file exists and if it does, add random SHA1 hash to the name.
while ($isfile($+(",%folder,%filename,"))) %filename = $+($gettok(%filename,-2--,46),_,$sha1(%filename $r(10000,99999)),.,$gettok(%filename,-1,46))
;Add file entry.
bset -t &h -1 $+(<p><a target="_blank" href="uploads/,$httpd.urlencode(%filename),">,$httpd.safe(%filename),</a> ( $+ $bytes($file(%tempfile).size).suf $+ )</p>)
;Rename and move the temporary file to the uploads folder.
.rename -o %tempfile $+(",%folder,%filename,")
}
else {
;File type wasn't in the accepted file type list.
bset -t &h -1 $+(<p><s>,$httpd.safe(%filename),</s> (disallowed filet type)</p>)
}
;Next hash.
tokenize 32 $2-
}
bset -t &h -1 </fieldset>
}
;Link to the uploads folder.
bset -t &h -1 <p><a target="_blank" href="uploads\">Browse uploads</a></p>
bset -t &h -1 </body></html>
;And now, let's send it all to the client.
httpd.send $sockname
}
/*
http://127.0.0.1/chunked
Example of chunked transfer-encoding.
"$httpd.chunkedheader" identifier must be checked at the start of the page.
The identifier returns 1 for success, and 0 for failure. Failure can occur when
the client sends a HEAD request, in which case only the header is sent.
Call "httpd.sendchunked <sockname>" alias whenever you have some data to send.
Call "httpd.stopchunked <sockname>" alias when you want to end the stream.
Always make sure the socket exists before you call send/stop/reset commands.
Note: the socket will automatically be closed after a set amount of time.
Check "Keep-Alive time" in "Limitations" section in settings. (/HTTPD LIMITATIONS)
You can reset the idle time by calling "httpd.resetchunk <sockname>" command.
*/
alias httpd.page./chunked {
;Checking if chunked transfer can continue.
if ($httpd.chunkedheader) {
;Change the content-type header to text/html.
hadd $sockname Content-Type text/html; charset=utf-8
;Start of the HTML code.
bset -t &h -1 <!DOCTYPE html><html><head><title>Chunked test</title></head><body>
bset -t &h -1 <h2>A mighty short story</h2>
;Let's send t he start of the HTML code.
;Note: at this point of the process, the socket will always exist.
httpd.sendchunked $sockname
;Set the story token number to 0.
hadd %c.httpd.name storypart 0
;Start a timer to play out rest of the story.
.timerhttpd.chunked. $+ $sockname 0 2 chunked.part $sockname
}
}
alias -l chunked.part {
;Check if the socket still exists.
if ($sock($1)) {
;Increase story token number by one.
hinc $1 storypart
;Set the full story to %story variable.
set -l %story Once upon a time...|There was a little HTTPd...|Written in mSL...|One day it decided to go on a little journey...|The little journey took it to chunked land...|In the chunked land the little HTTPd chunked chunks...|When it finally ran out of chunks...|It said goodbye and farewell.
;Check if the current story token exists.
if ($gettok(%story,$hget($1,storypart),124)) {
;Set the story token to &h bvar.
bset -t &h -1 $+(<p>,$v1,</p>)
;Send the data to the client.
httpd.sendchunked $1
}
else {
;No more tokens left to send, end the story.
bset -t &h -1 The end.</body></html>
;Send the end.
httpd.sendchunked $1
;Stop the chunked transfer.
httpd.stopchunked $1
;Stop the timer.
.timerhttpd.chunked. $+ $1 off
}
}
;Turn the timer off if the socket doesn't exist.
else .timerhttpd.chunked. $+ $1 off
}