Last active
November 28, 2022 15:03
-
-
Save mitsuoka/2659496 to your computer and use it in GitHub Desktop.
Dart code sample: Simple file server and MIME type library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Dart code sample: Simple file server and MIME types library | |
*** Caution *** | |
Do not use this code for actual applications. You should use secure connection | |
and limit access to restricted areas of your file system. | |
Usage: | |
1. Download, uncompress and rename the folder to "FileDownloadServer". | |
2. Put files you want to send into the folder. | |
3. From Dart Editor, File > Open Folder and select this FileDownloadServer folder. | |
4. Run the FileServer.dart as server. | |
5. Access the server from your browser: | |
http://localhost:8080/fserver (Downloading though the download page. Enter the | |
file_name and click the submit button) | |
or, http://localhost:8080/fserver/file_name (Direct downloading) | |
How to specify the file_name: | |
You can specify the file_name using relative path or absolute path. For example, | |
let “C:/dart_apps_server/FileDownloadServer” is the folder path of the file | |
server and the “readme.text” file is placed in the same folder. Then “readme.text” | |
is equivalent to “C:/dart_apps_server/FileDownloadServer/readme.text”. | |
Likewise, “test/jpegImage.jpg” is equivalent to | |
“C:/dart_apps_server/FileDownloadServer/test/jpegImage.jpg”. | |
Description like “../HelloWorld/HelloWorld.dart” is limited to the download page | |
and that is equivalent to “C:/dart_apps_server/HelloWorld/HelloWorld.dart”. | |
In case of downloading HTML files through the download page, browsers will not execute | |
scripts in the downloaded HTML file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Request a File</title> | |
</head> | |
<body> | |
<h1>Request a file</h1> | |
<h2>Enter the file name to download</h2> | |
<!-- Modify following lines for your application --> | |
<form method="get" action="http://localhost:8080/fserver"> | |
<input type="text" name="fileName" value="readme.txt" size="50"> | |
<br> | |
<input type="submit" value=" Submit "> | |
</form> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Dart code sample: Simple file server | |
1. Download, uncompress and rename the folder to 'FileDownloadServer'. | |
2. Put files you want to send into the folder. | |
3. From Dart Editor, File > Open Folder and select this FileDownloadServer folder. | |
4. Run the FileServer.dart as server. | |
5. Access the server from Chrome: http://localhost:8080/fserver | |
or directly: http://localhost:8080/fserver/readme.txt | |
Ref. | |
https://gist.github.com/2564561 | |
https://gist.github.com/2564562 | |
http://www.cresc.co.jp/tech/java/Google_Dart/DartLanguageGuide.pdf (in Japanese) | |
Modified May 2012, by Terry Mitsuoka. | |
Revised July 2012 to include MIME library. | |
Revised Sept. 2012 to incorporate catch syntax change. | |
Revised Oct. 2012 to incorporate M1 changes. | |
Revised Feb. 2013 to incorporate newly added dart:async library. | |
Revised Feb. 2013 to incorporate M3 changes. | |
March 2013, API changes (String and HttpResponse) fixed | |
*/ | |
import 'dart:io'; | |
import 'MIME.dart' as mime; | |
import "dart:utf" as utf; | |
import 'dart:async'; | |
final HOST = '127.0.0.1'; | |
final PORT = 8080; | |
final REQUEST_PATH = "/fserver"; | |
final LOG_REQUESTS = true; | |
void main() { | |
HttpServer.bind(HOST, PORT) | |
.then((HttpServer server) { | |
server.listen( | |
(HttpRequest request) { | |
if (request.uri.path == REQUEST_PATH) { | |
requestReceivedHandler(request); | |
} | |
}); | |
print("Serving $REQUEST_PATH on http://${HOST}:${PORT}."); | |
}); | |
} | |
void requestReceivedHandler(HttpRequest request) { | |
HttpResponse response = request.response; | |
String bodyString = ""; // request body byte data | |
var completer = new Completer(); | |
if (request.method == "GET") { completer.complete("query string data received"); | |
} else if (request.method == "POST") { | |
request | |
.transform(new StringDecoder()) | |
.listen( | |
(String str){bodyString = bodyString + str;}, | |
onDone: (){ | |
completer.complete("body data received");}, | |
onError: (e){ | |
print('exeption occured : ${e.toString()}');} | |
); | |
} | |
else { | |
response.statusCode = HttpStatus.METHOD_NOT_ALLOWED; | |
response.close(); | |
return; | |
} | |
// process the request | |
completer.future.then((data){ | |
if (LOG_REQUESTS) { | |
print(createLogMessage(request, bodyString)); | |
} | |
if (request.queryParameters['fileName'] != null) { | |
new FileHandler().onRequest(request, response); | |
} else | |
{ | |
String fName = request.uri.path.replaceFirst(REQUEST_PATH, ''); | |
if (fName.length > 2) { | |
fName = fName.substring(1); | |
new FileHandler().onRequest(request, response, fName); | |
} | |
else { new FileHandler().onRequest(request, response, 'Client.html'); | |
} | |
} | |
}); | |
} | |
class FileHandler { | |
FileHandler(){ | |
} | |
void onRequest(HttpRequest request, HttpResponse response, [String fileName = null]) { | |
try { | |
if (fileName == null) { | |
fileName = request.queryParameters['fileName']; | |
} | |
if (LOG_REQUESTS) { | |
print('Requested file name : $fileName'); | |
} | |
File file = new File(fileName); | |
if (file.existsSync()) { | |
String mimeType = 'text/html; charset=UTF-8'; | |
int lastDot = fileName.lastIndexOf('.', fileName.length - 1); | |
if (lastDot != -1) { | |
String extension = fileName.substring(lastDot + 1); | |
mimeType = mime.mimeType(extension); | |
} | |
response.headers.set('Content-Type', mimeType); | |
// response.headers.set('Content-Disposition', 'attachment; filename=\'${fileName}\''); | |
// Get the length of the file for setting the Content-Length header. | |
RandomAccessFile openedFile = file.openSync(); | |
response.contentLength = openedFile.lengthSync(); | |
openedFile.closeSync(); | |
// Pipe the file content into the response. | |
file.openRead().pipe(response); | |
} else { | |
if (LOG_REQUESTS) { | |
print('File not found: $fileName'); | |
} | |
new NotFoundHandler().onRequest(request, response); | |
} | |
} on Exception catch (err) { | |
print('File Handler error : $err.toString()'); | |
} | |
} | |
} | |
class NotFoundHandler { | |
NotFoundHandler(){ | |
} | |
static final String notFoundPageHtml = ''' | |
<html><head> | |
<title>404 Not Found</title> | |
</head><body> | |
<h1>Not Found</h1> | |
<p>The requested URL or File was not found on this server.</p> | |
</body></html>'''; | |
void onRequest(HttpRequest request, HttpResponse response){ | |
response | |
..statusCode = HttpStatus.NOT_FOUND | |
..headers.set('Content-Type', 'text/html; charset=UTF-8') | |
..write(notFoundPageHtml) | |
..close(); | |
} | |
} | |
// create log message | |
StringBuffer createLogMessage(HttpRequest request, [String bodyString]) { | |
var sb = new StringBuffer( '''request.headers.host : ${request.headers.host} | |
request.headers.port : ${request.headers.port} | |
request.connectionInfo.localPort : ${request.connectionInfo.localPort} | |
request.connectionInfo.remoteHost : ${request.connectionInfo.remoteHost} | |
request.connectionInfo.remotePort : ${request.connectionInfo.remotePort} | |
request.method : ${request.method} | |
request.persistentConnection : ${request.persistentConnection} | |
request.protocolVersion : ${request.protocolVersion} | |
request.contentLength : ${request.contentLength} | |
request.uri : ${request.uri} | |
request.uri.path : ${request.uri.path} | |
request.uri.query : ${request.uri.query} | |
request.uri.queryParameters : | |
'''); | |
request.queryParameters.forEach((key, value){ | |
sb.write(" ${key} : ${value}\n"); | |
}); | |
sb.write('''request.cookies : | |
'''); | |
request.cookies.forEach((value){ | |
sb.write(" ${value.toString()}\n"); | |
}); | |
sb.write('''request.headers.expires : ${request.headers.expires} | |
request.headers : | |
'''); | |
var str = request.headers.toString(); | |
for (int i = 0; i < str.length - 1; i++){ | |
if (str[i] == "\n") { sb.write("\n "); | |
} else { sb.write(str[i]); | |
} | |
} | |
sb.write('''\nrequest.session.id : ${request.session.id} | |
requset.session.isNew : ${request.session.isNew} | |
'''); | |
if (request.method == "POST") { | |
var enctype = request.headers["content-type"]; | |
if (enctype[0].contains("text")) { | |
sb.write("request body string : ${bodyString.replaceAll('+', ' ')}"); | |
} else if (enctype[0].contains("urlencoded")) { | |
sb.write("request body string (URL decoded): ${urlDecode(bodyString)}"); | |
} | |
} | |
sb.write("\n"); | |
return sb; | |
} | |
// make safe string buffer data as HTML text | |
StringBuffer makeSafe(StringBuffer b) { | |
var s = b.toString(); | |
b = new StringBuffer(); | |
for (int i = 0; i < s.length; i++){ | |
if (s[i] == '&') { b.write('&'); | |
} else if (s[i] == '"') { b.write('"'); | |
} else if (s[i] == "'") { b.write('''); | |
} else if (s[i] == '<') { b.write('<'); | |
} else if (s[i] == '>') { b.write('>'); | |
} else { b.write(s[i]); | |
} | |
} | |
return b; | |
} | |
// URL decoder decodes url encoded utf-8 bytes | |
// Use this method to decode query string | |
// We need this kind of encoder and decoder with optional [encType] argument | |
String urlDecode(String s){ | |
int i, p, q; | |
var ol = new List<int>(); | |
for (i = 0; i < s.length; i++) { | |
if (s[i].codeUnitAt(0) == 0x2b) { ol.add(0x20); // convert + to space | |
} else if (s[i].codeUnitAt(0) == 0x25) { // convert hex bytes to a single bite | |
i++; | |
p = s[i].toUpperCase().codeUnitAt(0) - 0x30; | |
if (p > 9) p = p - 7; | |
i++; | |
q = s[i].toUpperCase().codeUnitAt(0) - 0x30; | |
if (q > 9) q = q - 7; | |
ol.add(p * 16 + q); | |
} | |
else { ol.add(s[i].codeUnitAt(0)); | |
} | |
} | |
return utf.decodeUtf8(ol); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
library MIME; | |
// get MIME type (returns null if there is no such extension) | |
String mimeType(String extension) => _mimeMaps[extension]; | |
// default MIME type mappings | |
Map _mimeMaps = const { | |
'abs': 'audio/x-mpeg', | |
'ai': 'application/postscript', | |
'aif': 'audio/x-aiff', | |
'aifc': 'audio/x-aiff', | |
'aiff': 'audio/x-aiff', | |
'aim': 'application/x-aim', | |
'art': 'image/x-jg', | |
'asf': 'video/x-ms-asf', | |
'asx': 'video/x-ms-asf', | |
'au': 'audio/basic', | |
'avi': 'video/x-msvideo', | |
'avx': 'video/x-rad-screenplay', | |
'bcpio': 'application/x-bcpio', | |
'bin': 'application/octet-stream', | |
'bmp': 'image/bmp', | |
'body': 'text/html', | |
'cdf': 'application/x-cdf', | |
'cer': 'application/x-x509-ca-cert', | |
'class': 'application/java', | |
'cpio': 'application/x-cpio', | |
'csh': 'application/x-csh', | |
'css': 'text/css', | |
'dart': 'application/vnd.dart', | |
'dib': 'image/bmp', | |
'doc': 'application/msword', | |
'docm': 'application/vnd.ms-word.document.macroEnabled.12', | |
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', | |
'dot': 'application/msword', | |
'dotm': 'application/vnd.ms-word.template.macroEnabled.12', | |
'dotx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', | |
'dtd': 'application/xml-dtd', | |
'dv': 'video/x-dv', | |
'dvi': 'application/x-dvi', | |
'eps': 'application/postscript', | |
'etx': 'text/x-setext', | |
'exe': 'application/octet-stream', | |
'gif': 'image/gif', | |
'gtar': 'application/x-gtar', | |
'gz': 'application/x-gzip', | |
'hdf': 'application/x-hdf', | |
'hqx': 'application/mac-binhex40', | |
'htc': 'text/x-component', | |
'htm': 'text/html', | |
'html': 'text/html', | |
'ico': 'image/vnd.microsoft.icon', | |
'ief': 'image/ief', | |
'jad': 'text/vnd.sun.j2me.app-descriptor', | |
'jar': 'application/java-archive', | |
'java': 'text/plain', | |
'jnlp': 'application/x-java-jnlp-file', | |
'jpe': 'image/jpeg', | |
'jpeg': 'image/jpeg', | |
'jpg': 'image/jpeg', | |
'js': 'text/javascript', | |
'jsf': 'text/plain', | |
'jspf': 'text/plain', | |
'kar': 'audio/x-midi', | |
'latex': 'application/x-latex', | |
'm3u': 'audio/x-mpegurl', | |
'mac': 'image/x-macpaint', | |
'man': 'application/x-troff-man', | |
'mathml': 'application/mathml+xml', | |
'me': 'application/x-troff-me', | |
'mid': 'audio/x-midi', | |
'midi': 'audio/x-midi', | |
'mif': 'application/x-mif', | |
'mov': 'video/quicktime', | |
'movie': 'video/x-sgi-movie', | |
'mp1': 'audio/x-mpeg', | |
'mp2': 'audio/x-mpeg', | |
'mp3': 'audio/x-mpeg', | |
'mp4': 'video/mp4', | |
'mpa': 'audio/x-mpeg', | |
'mpe': 'video/mpeg', | |
'mpeg': 'video/mpeg', | |
'mpega': 'audio/x-mpeg', | |
'mpg': 'video/mpeg', | |
'mpv2': 'video/mpeg2', | |
'ms': 'application/x-wais-source', | |
'nc': 'application/x-netcdf', | |
'oda': 'application/oda', | |
'odb': 'application/vnd.oasis.opendocument.database', | |
'odc': 'application/vnd.oasis.opendocument.chart', | |
'odf': 'application/vnd.oasis.opendocument.formula', | |
'odg': 'application/vnd.oasis.opendocument.graphics', | |
'odi': 'application/vnd.oasis.opendocument.image', | |
'odm': 'application/vnd.oasis.opendocument.text-master', | |
'odp': 'application/vnd.oasis.opendocument.presentation', | |
'ods': 'application/vnd.oasis.opendocument.spreadsheet', | |
'odt': 'application/vnd.oasis.opendocument.text', | |
'otg': 'application/vnd.oasis.opendocument.graphics-template', | |
'oth': 'application/vnd.oasis.opendocument.text-web', | |
'otp': 'application/vnd.oasis.opendocument.presentation-template', | |
'ots': 'application/vnd.oasis.opendocument.spreadsheet-template', | |
'ott': 'application/vnd.oasis.opendocument.text-template', | |
'ogx': 'application/ogg', | |
'ogv': 'video/ogg', | |
'oga': 'audio/ogg', | |
'ogg': 'audio/ogg', | |
'spx': 'audio/ogg', | |
'flac': 'audio/flac', | |
'anx': 'application/annodex', | |
'axa': 'audio/annodex', | |
'axv': 'video/annodex', | |
'xspf': 'application/xspf+xml', | |
'pbm': 'image/x-portable-bitmap', | |
'pct': 'image/pict', | |
'pdf': 'application/pdf', | |
'pgm': 'image/x-portable-graymap', | |
'pic': 'image/pict', | |
'pict': 'image/pict', | |
'pls': 'audio/x-scpls', | |
'png': 'image/png', | |
'pnm': 'image/x-portable-anymap', | |
'pnt': 'image/x-macpaint', | |
'ppm': 'image/x-portable-pixmap', | |
'ppt': 'application/vnd.ms-powerpoint', | |
'pot': 'application/vnd.ms-powerpoint', | |
'pps': 'application/vnd.ms-powerpoint', | |
'ppa': 'application/vnd.ms-powerpoint', | |
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', | |
'potx': 'application/vnd.openxmlformats-officedocument.presentationml.template', | |
'ppsx': 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', | |
'ppam': 'application/vnd.ms-powerpoint.addin.macroEnabled.12', | |
'pptm': 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', | |
'potm': 'application/vnd.ms-powerpoint.template.macroEnabled.12', | |
'ppsm': 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', | |
'ps': 'application/postscript', | |
'psd': 'image/x-photoshop', | |
'qt': 'video/quicktime', | |
'qti': 'image/x-quicktime', | |
'qtif': 'image/x-quicktime', | |
'ras': 'image/x-cmu-raster', | |
'rdf': 'application/rdf+xml', | |
'rgb': 'image/x-rgb', | |
'rm': 'application/vnd.rn-realmedia', | |
'roff': 'application/x-troff', | |
'rtf': 'application/rtf', | |
'rtx': 'text/richtext', | |
'sh': 'application/x-sh', | |
'shar': 'application/x-shar', | |
// 'shtml': 'text/x-server-parsed-html', | |
'smf': 'audio/x-midi', | |
'sit': 'application/x-stuffit', | |
'snd': 'audio/basic', | |
'src': 'application/x-wais-source', | |
'sv4cpio': 'application/x-sv4cpio', | |
'sv4crc': 'application/x-sv4crc', | |
'svg': 'image/svg+xml', | |
'svgz': 'image/svg+xml', | |
'swf': 'application/x-shockwave-flash', | |
't': 'application/x-troff', | |
'tar': 'application/x-tar', | |
'tcl': 'application/x-tcl', | |
'tex': 'application/x-tex', | |
'texi': 'application/x-texinfo', | |
'texinfo': 'application/x-texinfo', | |
'tif': 'image/tiff', | |
'tiff': 'image/tiff', | |
'tr': 'application/x-troff', | |
'tsv': 'text/tab-separated-values', | |
'txt': 'text/plain', | |
'ulw': 'audio/basic', | |
'ustar': 'application/x-ustar', | |
'vxml': 'application/voicexml+xml', | |
'xbm': 'image/x-xbitmap', | |
'xht': 'application/xhtml+xml', | |
'xhtml': 'application/xhtml+xml', | |
'xls': 'application/vnd.ms-excel', | |
'xlt': 'application/vnd.ms-excel', | |
'xla': 'application/vnd.ms-excel', | |
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', | |
'xltx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', | |
'xlsm': 'application/vnd.ms-excel.sheet.macroEnabled.12', | |
'xltm': 'application/vnd.ms-excel.template.macroEnabled.12', | |
'xlam': 'application/vnd.ms-excel.addin.macroEnabled.12', | |
'xlsb': 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', | |
'xml': 'application/xml', | |
'xpm': 'image/x-xpixmap', | |
'xsl': 'application/xml', | |
'xslt': 'application/xslt+xml', | |
'xul': 'application/vnd.mozilla.xul+xml', | |
'xwd': 'image/x-xwindowdump', | |
'vsd': 'application/x-visio', | |
'war': 'application/java-archive', | |
'wav': 'audio/x-wav', | |
'wbmp': 'image/vnd.wap.wbmp', | |
'wml': 'text/vnd.wap.wml', | |
'wmlc': 'application/vnd.wap.wmlc', | |
'wmls': 'text/vnd.wap.wmlscript', | |
'wmlscriptc': 'application/vnd.wap.wmlscriptc', | |
'wmv': 'video/x-ms-wmv', | |
'wrl': 'x-world/x-vrml', | |
'wspolicy': 'application/wspolicy+xml', | |
'Z': 'application/x-compress', | |
'z': 'application/x-compress', | |
'zip': 'application/zip' | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment