From a0bb721abb54c2406d27045a2db503e71993c07c Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Sun, 21 Oct 2018 20:33:11 +0300 Subject: [PATCH 01/14] fix only root wildcard but no '/' registered --- README.md | 2 +- mime.go | 597 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ trie.go | 8 +- 3 files changed, 605 insertions(+), 2 deletions(-) create mode 100644 mime.go diff --git a/README.md b/README.md index a8c8d3a..ca3b9d2 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@
- Release/stability diff --git a/mime.go b/mime.go new file mode 100644 index 0000000..2c11ebb --- /dev/null +++ b/mime.go @@ -0,0 +1,597 @@ +package muxie + +import ( + "mime" + "path/filepath" +) + +var types = map[string]string{ + ".3dm": "x-world/x-3dmf", + ".3dmf": "x-world/x-3dmf", + ".7z": "application/x-7z-compressed", + ".a": "application/octet-stream", + ".aab": "application/x-authorware-bin", + ".aam": "application/x-authorware-map", + ".aas": "application/x-authorware-seg", + ".abc": "text/vndabc", + ".ace": "application/x-ace-compressed", + ".acgi": "text/html", + ".afl": "video/animaflex", + ".ai": "application/postscript", + ".aif": "audio/aiff", + ".aifc": "audio/aiff", + ".aiff": "audio/aiff", + ".aim": "application/x-aim", + ".aip": "text/x-audiosoft-intra", + ".alz": "application/x-alz-compressed", + ".ani": "application/x-navi-animation", + ".aos": "application/x-nokia-9000-communicator-add-on-software", + ".aps": "application/mime", + ".apk": "application/vnd.android.package-archive", + ".arc": "application/x-arc-compressed", + ".arj": "application/arj", + ".art": "image/x-jg", + ".asf": "video/x-ms-asf", + ".asm": "text/x-asm", + ".asp": "text/asp", + ".asx": "application/x-mplayer2", + ".au": "audio/basic", + ".avi": "video/x-msvideo", + ".avs": "video/avs-video", + ".bcpio": "application/x-bcpio", + ".bin": "application/mac-binary", + ".bmp": "image/bmp", + ".boo": "application/book", + ".book": "application/book", + ".boz": "application/x-bzip2", + ".bsh": "application/x-bsh", + ".bz2": "application/x-bzip2", + ".bz": "application/x-bzip", + ".c++": "text/plain", + ".c": "text/x-c", + ".cab": "application/vnd.ms-cab-compressed", + ".cat": "application/vndms-pkiseccat", + ".cc": "text/x-c", + ".ccad": "application/clariscad", + ".cco": "application/x-cocoa", + ".cdf": "application/cdf", + ".cer": "application/pkix-cert", + ".cha": "application/x-chat", + ".chat": "application/x-chat", + ".chrt": "application/vnd.kde.kchart", + ".class": "application/java", + ".com": "text/plain", + ".conf": "text/plain", + ".cpio": "application/x-cpio", + ".cpp": "text/x-c", + ".cpt": "application/mac-compactpro", + ".crl": "application/pkcs-crl", + ".crt": "application/pkix-cert", + ".crx": "application/x-chrome-extension", + ".csh": "text/x-scriptcsh", + ".css": "text/css", + ".csv": "text/csv", + ".cxx": "text/plain", + ".dar": "application/x-dar", + ".dcr": "application/x-director", + ".deb": "application/x-debian-package", + ".deepv": "application/x-deepv", + ".def": "text/plain", + ".der": "application/x-x509-ca-cert", + ".dif": "video/x-dv", + ".dir": "application/x-director", + ".divx": "video/divx", + ".dl": "video/dl", + ".dmg": "application/x-apple-diskimage", + ".doc": "application/msword", + ".dot": "application/msword", + ".dp": "application/commonground", + ".drw": "application/drafting", + ".dump": "application/octet-stream", + ".dv": "video/x-dv", + ".dvi": "application/x-dvi", + ".dwf": "drawing/x-dwf=(old)", + ".dwg": "application/acad", + ".dxf": "application/dxf", + ".dxr": "application/x-director", + ".el": "text/x-scriptelisp", + ".elc": "application/x-bytecodeelisp=(compiled=elisp)", + ".eml": "message/rfc822", + ".env": "application/x-envoy", + ".eps": "application/postscript", + ".es": "application/x-esrehber", + ".etx": "text/x-setext", + ".evy": "application/envoy", + ".exe": "application/octet-stream", + ".f77": "text/x-fortran", + ".f90": "text/x-fortran", + ".f": "text/x-fortran", + ".fdf": "application/vndfdf", + ".fif": "application/fractals", + ".fli": "video/fli", + ".flo": "image/florian", + ".flv": "video/x-flv", + ".flx": "text/vndfmiflexstor", + ".fmf": "video/x-atomic3d-feature", + ".for": "text/x-fortran", + ".fpx": "image/vndfpx", + ".frl": "application/freeloader", + ".funk": "audio/make", + ".g3": "image/g3fax", + ".g": "text/plain", + ".gif": "image/gif", + ".gl": "video/gl", + ".gsd": "audio/x-gsm", + ".gsm": "audio/x-gsm", + ".gsp": "application/x-gsp", + ".gss": "application/x-gss", + ".gtar": "application/x-gtar", + ".gz": "application/x-compressed", + ".gzip": "application/x-gzip", + ".h": "text/x-h", + ".hdf": "application/x-hdf", + ".help": "application/x-helpfile", + ".hgl": "application/vndhp-hpgl", + ".hh": "text/x-h", + ".hlb": "text/x-script", + ".hlp": "application/hlp", + ".hpg": "application/vndhp-hpgl", + ".hpgl": "application/vndhp-hpgl", + ".hqx": "application/binhex", + ".hta": "application/hta", + ".htc": "text/x-component", + ".htm": "text/html", + ".html": "text/html", + ".htmls": "text/html", + ".htt": "text/webviewhtml", + ".htx": "text/html", + ".ice": "x-conference/x-cooltalk", + ".ico": "image/x-icon", + ".ics": "text/calendar", + ".icz": "text/calendar", + ".idc": "text/plain", + ".ief": "image/ief", + ".iefs": "image/ief", + ".iges": "application/iges", + ".igs": "application/iges", + ".ima": "application/x-ima", + ".imap": "application/x-httpd-imap", + ".inf": "application/inf", + ".ins": "application/x-internett-signup", + ".ip": "application/x-ip2", + ".isu": "video/x-isvideo", + ".it": "audio/it", + ".iv": "application/x-inventor", + ".ivr": "i-world/i-vrml", + ".ivy": "application/x-livescreen", + ".jam": "audio/x-jam", + ".jav": "text/x-java-source", + ".java": "text/x-java-source", + ".jcm": "application/x-java-commerce", + ".jfif-tbnl": "image/jpeg", + ".jfif": "image/jpeg", + ".jnlp": "application/x-java-jnlp-file", + ".jpe": "image/jpeg", + ".jpeg": "image/jpeg", + ".jpg": "image/jpeg", + ".jps": "image/x-jps", + ".js": "application/javascript", + ".json": "application/json", + ".jut": "image/jutvision", + ".kar": "audio/midi", + ".karbon": "application/vnd.kde.karbon", + ".kfo": "application/vnd.kde.kformula", + ".flw": "application/vnd.kde.kivio", + ".kml": "application/vnd.google-earth.kml+xml", + ".kmz": "application/vnd.google-earth.kmz", + ".kon": "application/vnd.kde.kontour", + ".kpr": "application/vnd.kde.kpresenter", + ".kpt": "application/vnd.kde.kpresenter", + ".ksp": "application/vnd.kde.kspread", + ".kwd": "application/vnd.kde.kword", + ".kwt": "application/vnd.kde.kword", + ".ksh": "text/x-scriptksh", + ".la": "audio/nspaudio", + ".lam": "audio/x-liveaudio", + ".latex": "application/x-latex", + ".lha": "application/lha", + ".lhx": "application/octet-stream", + ".list": "text/plain", + ".lma": "audio/nspaudio", + ".log": "text/plain", + ".lsp": "text/x-scriptlisp", + ".lst": "text/plain", + ".lsx": "text/x-la-asf", + ".ltx": "application/x-latex", + ".lzh": "application/octet-stream", + ".lzx": "application/lzx", + ".m1v": "video/mpeg", + ".m2a": "audio/mpeg", + ".m2v": "video/mpeg", + ".m3u": "audio/x-mpegurl", + ".m": "text/x-m", + ".man": "application/x-troff-man", + ".manifest": "text/cache-manifest", + ".map": "application/x-navimap", + ".mar": "text/plain", + ".mbd": "application/mbedlet", + ".mc$": "application/x-magic-cap-package-10", + ".mcd": "application/mcad", + ".mcf": "text/mcf", + ".mcp": "application/netmc", + ".me": "application/x-troff-me", + ".mht": "message/rfc822", + ".mhtml": "message/rfc822", + ".mid": "application/x-midi", + ".midi": "application/x-midi", + ".mif": "application/x-frame", + ".mime": "message/rfc822", + ".mjf": "audio/x-vndaudioexplosionmjuicemediafile", + ".mjpg": "video/x-motion-jpeg", + ".mm": "application/base64", + ".mme": "application/base64", + ".mod": "audio/mod", + ".moov": "video/quicktime", + ".mov": "video/quicktime", + ".movie": "video/x-sgi-movie", + ".mp2": "audio/mpeg", + ".mp3": "audio/mpeg", + ".mp4": "video/mp4", + ".mpa": "audio/mpeg", + ".mpc": "application/x-project", + ".mpe": "video/mpeg", + ".mpeg": "video/mpeg", + ".mpg": "video/mpeg", + ".mpga": "audio/mpeg", + ".mpp": "application/vndms-project", + ".mpt": "application/x-project", + ".mpv": "application/x-project", + ".mpx": "application/x-project", + ".mrc": "application/marc", + ".ms": "application/x-troff-ms", + ".mv": "video/x-sgi-movie", + ".my": "audio/make", + ".mzz": "application/x-vndaudioexplosionmzz", + ".nap": "image/naplps", + ".naplps": "image/naplps", + ".nc": "application/x-netcdf", + ".ncm": "application/vndnokiaconfiguration-message", + ".nif": "image/x-niff", + ".niff": "image/x-niff", + ".nix": "application/x-mix-transfer", + ".nsc": "application/x-conference", + ".nvd": "application/x-navidoc", + ".o": "application/octet-stream", + ".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", + ".oga": "audio/ogg", + ".ogg": "audio/ogg", + ".ogv": "video/ogg", + ".omc": "application/x-omc", + ".omcd": "application/x-omcdatamaker", + ".omcr": "application/x-omcregerator", + ".otc": "application/vnd.oasis.opendocument.chart-template", + ".otf": "application/vnd.oasis.opendocument.formula-template", + ".otg": "application/vnd.oasis.opendocument.graphics-template", + ".oth": "application/vnd.oasis.opendocument.text-web", + ".oti": "application/vnd.oasis.opendocument.image-template", + ".otm": "application/vnd.oasis.opendocument.text-master", + ".otp": "application/vnd.oasis.opendocument.presentation-template", + ".ots": "application/vnd.oasis.opendocument.spreadsheet-template", + ".ott": "application/vnd.oasis.opendocument.text-template", + ".p10": "application/pkcs10", + ".p12": "application/pkcs-12", + ".p7a": "application/x-pkcs7-signature", + ".p7c": "application/pkcs7-mime", + ".p7m": "application/pkcs7-mime", + ".p7r": "application/x-pkcs7-certreqresp", + ".p7s": "application/pkcs7-signature", + ".p": "text/x-pascal", + ".part": "application/pro_eng", + ".pas": "text/pascal", + ".pbm": "image/x-portable-bitmap", + ".pcl": "application/vndhp-pcl", + ".pct": "image/x-pict", + ".pcx": "image/x-pcx", + ".pdb": "chemical/x-pdb", + ".pdf": "application/pdf", + ".pfunk": "audio/make", + ".pgm": "image/x-portable-graymap", + ".pic": "image/pict", + ".pict": "image/pict", + ".pkg": "application/x-newton-compatible-pkg", + ".pko": "application/vndms-pkipko", + ".pl": "text/x-scriptperl", + ".plx": "application/x-pixclscript", + ".pm4": "application/x-pagemaker", + ".pm5": "application/x-pagemaker", + ".pm": "text/x-scriptperl-module", + ".png": "image/png", + ".pnm": "application/x-portable-anymap", + ".pot": "application/mspowerpoint", + ".pov": "model/x-pov", + ".ppa": "application/vndms-powerpoint", + ".ppm": "image/x-portable-pixmap", + ".pps": "application/mspowerpoint", + ".ppt": "application/mspowerpoint", + ".ppz": "application/mspowerpoint", + ".pre": "application/x-freelance", + ".prt": "application/pro_eng", + ".ps": "application/postscript", + ".psd": "application/octet-stream", + ".pvu": "paleovu/x-pv", + ".pwz": "application/vndms-powerpoint", + ".py": "text/x-scriptphyton", + ".pyc": "application/x-bytecodepython", + ".qcp": "audio/vndqcelp", + ".qd3": "x-world/x-3dmf", + ".qd3d": "x-world/x-3dmf", + ".qif": "image/x-quicktime", + ".qt": "video/quicktime", + ".qtc": "video/x-qtc", + ".qti": "image/x-quicktime", + ".qtif": "image/x-quicktime", + ".ra": "audio/x-pn-realaudio", + ".ram": "audio/x-pn-realaudio", + ".rar": "application/x-rar-compressed", + ".ras": "application/x-cmu-raster", + ".rast": "image/cmu-raster", + ".rexx": "text/x-scriptrexx", + ".rf": "image/vndrn-realflash", + ".rgb": "image/x-rgb", + ".rm": "application/vndrn-realmedia", + ".rmi": "audio/mid", + ".rmm": "audio/x-pn-realaudio", + ".rmp": "audio/x-pn-realaudio", + ".rng": "application/ringing-tones", + ".rnx": "application/vndrn-realplayer", + ".roff": "application/x-troff", + ".rp": "image/vndrn-realpix", + ".rpm": "audio/x-pn-realaudio-plugin", + ".rt": "text/vndrn-realtext", + ".rtf": "text/richtext", + ".rtx": "text/richtext", + ".rv": "video/vndrn-realvideo", + ".s": "text/x-asm", + ".s3m": "audio/s3m", + ".s7z": "application/x-7z-compressed", + ".saveme": "application/octet-stream", + ".sbk": "application/x-tbook", + ".scm": "text/x-scriptscheme", + ".sdml": "text/plain", + ".sdp": "application/sdp", + ".sdr": "application/sounder", + ".sea": "application/sea", + ".set": "application/set", + ".sgm": "text/x-sgml", + ".sgml": "text/x-sgml", + ".sh": "text/x-scriptsh", + ".shar": "application/x-bsh", + ".shtml": "text/x-server-parsed-html", + ".sid": "audio/x-psid", + ".skd": "application/x-koan", + ".skm": "application/x-koan", + ".skp": "application/x-koan", + ".skt": "application/x-koan", + ".sit": "application/x-stuffit", + ".sitx": "application/x-stuffitx", + ".sl": "application/x-seelogo", + ".smi": "application/smil", + ".smil": "application/smil", + ".snd": "audio/basic", + ".sol": "application/solids", + ".spc": "text/x-speech", + ".spl": "application/futuresplash", + ".spr": "application/x-sprite", + ".sprite": "application/x-sprite", + ".spx": "audio/ogg", + ".src": "application/x-wais-source", + ".ssi": "text/x-server-parsed-html", + ".ssm": "application/streamingmedia", + ".sst": "application/vndms-pkicertstore", + ".step": "application/step", + ".stl": "application/sla", + ".stp": "application/step", + ".sv4cpio": "application/x-sv4cpio", + ".sv4crc": "application/x-sv4crc", + ".svf": "image/vnddwg", + ".svg": "image/svg+xml", + ".svr": "application/x-world", + ".swf": "application/x-shockwave-flash", + ".t": "application/x-troff", + ".talk": "text/x-speech", + ".tar": "application/x-tar", + ".tbk": "application/toolbook", + ".tcl": "text/x-scripttcl", + ".tcsh": "text/x-scripttcsh", + ".tex": "application/x-tex", + ".texi": "application/x-texinfo", + ".texinfo": "application/x-texinfo", + ".text": "text/plain", + ".tgz": "application/gnutar", + ".tif": "image/tiff", + ".tiff": "image/tiff", + ".tr": "application/x-troff", + ".tsi": "audio/tsp-audio", + ".tsp": "application/dsptype", + ".tsv": "text/tab-separated-values", + ".turbot": "image/florian", + ".txt": "text/plain", + ".uil": "text/x-uil", + ".uni": "text/uri-list", + ".unis": "text/uri-list", + ".unv": "application/i-deas", + ".uri": "text/uri-list", + ".uris": "text/uri-list", + ".ustar": "application/x-ustar", + ".uu": "text/x-uuencode", + ".uue": "text/x-uuencode", + ".vcd": "application/x-cdlink", + ".vcf": "text/x-vcard", + ".vcard": "text/x-vcard", + ".vcs": "text/x-vcalendar", + ".vda": "application/vda", + ".vdo": "video/vdo", + ".vew": "application/groupwise", + ".viv": "video/vivo", + ".vivo": "video/vivo", + ".vmd": "application/vocaltec-media-desc", + ".vmf": "application/vocaltec-media-file", + ".voc": "audio/voc", + ".vos": "video/vosaic", + ".vox": "audio/voxware", + ".vqe": "audio/x-twinvq-plugin", + ".vqf": "audio/x-twinvq", + ".vql": "audio/x-twinvq-plugin", + ".vrml": "application/x-vrml", + ".vrt": "x-world/x-vrt", + ".vsd": "application/x-visio", + ".vst": "application/x-visio", + ".vsw": "application/x-visio", + ".w60": "application/wordperfect60", + ".w61": "application/wordperfect61", + ".w6w": "application/msword", + ".wav": "audio/wav", + ".wb1": "application/x-qpro", + ".wbmp": "image/vnd.wap.wbmp", + ".web": "application/vndxara", + ".wiz": "application/msword", + ".wk1": "application/x-123", + ".wmf": "windows/metafile", + ".wml": "text/vnd.wap.wml", + ".wmlc": "application/vnd.wap.wmlc", + ".wmls": "text/vnd.wap.wmlscript", + ".wmlsc": "application/vnd.wap.wmlscriptc", + ".word": "application/msword", + ".wp5": "application/wordperfect", + ".wp6": "application/wordperfect", + ".wp": "application/wordperfect", + ".wpd": "application/wordperfect", + ".wq1": "application/x-lotus", + ".wri": "application/mswrite", + ".wrl": "application/x-world", + ".wrz": "model/vrml", + ".wsc": "text/scriplet", + ".wsrc": "application/x-wais-source", + ".wtk": "application/x-wintalk", + ".x-png": "image/png", + ".xbm": "image/x-xbitmap", + ".xdr": "video/x-amt-demorun", + ".xgz": "xgl/drawing", + ".xif": "image/vndxiff", + ".xl": "application/excel", + ".xla": "application/excel", + ".xlb": "application/excel", + ".xlc": "application/excel", + ".xld": "application/excel", + ".xlk": "application/excel", + ".xll": "application/excel", + ".xlm": "application/excel", + ".xls": "application/excel", + ".xlt": "application/excel", + ".xlv": "application/excel", + ".xlw": "application/excel", + ".xm": "audio/xm", + ".xml": "text/xml", + ".xmz": "xgl/movie", + ".xpix": "application/x-vndls-xpix", + ".xpm": "image/x-xpixmap", + ".xsr": "video/x-amt-showrun", + ".xwd": "image/x-xwd", + ".xyz": "chemical/x-pdb", + ".z": "application/x-compress", + ".zip": "application/zip", + ".zoo": "application/octet-stream", + ".zsh": "text/x-scriptzsh", + ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".docm": "application/vnd.ms-word.document.macroEnabled.12", + ".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + ".dotm": "application/vnd.ms-word.template.macroEnabled.12", + ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12", + ".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + ".xltm": "application/vnd.ms-excel.template.macroEnabled.12", + ".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12", + ".xlam": "application/vnd.ms-excel.addin.macroEnabled.12", + ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12", + ".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", + ".potx": "application/vnd.openxmlformats-officedocument.presentationml.template", + ".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12", + ".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12", + ".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", + ".sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12", + ".thmx": "application/vnd.ms-officetheme", + ".onetoc": "application/onenote", + ".onetoc2": "application/onenote", + ".onetmp": "application/onenote", + ".onepkg": "application/onenote", + ".xpi": "application/x-xpinstall", + ".wasm": "application/wasm", +} + +func init() { + for ext, typ := range types { + // skip errors + mime.AddExtensionType(ext, typ) + } +} + +// TypeByExtension returns the MIME type associated with the file extension ext. +// The extension ext should begin with a leading dot, as in ".html". +// When ext has no associated type, typeByExtension returns "". +// +// Extensions are looked up first case-sensitively, then case-insensitively. +// +// The built-in table is small but on unix it is augmented by the local +// system's mime.types file(s) if available under one or more of these +// names: +// +// /etc/mime.types +// /etc/apache2/mime.types +// /etc/apache/mime.types +// +// On Windows, MIME types are extracted from the registry. +// +// Text types have the charset parameter set to "utf-8" by default. +func TypeByExtension(ext string) (typ string) { + if len(ext) < 2 { + return + } + + if ext[0] != '.' { // try to take it by filename + typ = TypeByFilename(ext) + if typ == "" { + ext = "." + ext // if error or something wrong then prepend the dot + } + } + + if typ == "" { + typ = mime.TypeByExtension(ext) + } + + // mime.TypeByExtension returns as text/plain; | charset=utf-8 the static .js (not always) + if ext == ".js" && (typ == "text/plain" || typ == "text/plain; charset=utf-8") { + + if ext == ".js" { + typ = "application/javascript" + } + } + return typ +} + +// TypeByFilename same as TypeByExtension +// but receives a filename path instead. +func TypeByFilename(fullFilename string) string { + ext := filepath.Ext(fullFilename) + return TypeByExtension(ext) +} diff --git a/trie.go b/trie.go index 321139b..71b0681 100644 --- a/trie.go +++ b/trie.go @@ -240,7 +240,13 @@ func (t *Trie) Search(q string, params ParamsSetter) *Node { end := len(q) if end == 0 || (end == 1 && q[0] == pathSepB) { - return t.root.getChild(pathSep) + // fixes only root wildcard but no / registered at. + if n := t.root.getChild(pathSep); n != nil { + return n + } + + q = pathSep + // } n := t.root From 712688b204ee73f937c30fa1fa77a8f6d4f7f72f Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Sun, 21 Oct 2018 20:52:01 +0300 Subject: [PATCH 02/14] fix root wildcard but no '/' registered but requested --- README.md | 2 +- mime.go | 597 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ node.go | 2 +- trie.go | 16 +- 4 files changed, 614 insertions(+), 3 deletions(-) create mode 100644 mime.go diff --git a/README.md b/README.md index a8c8d3a..ca3b9d2 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@
- Release/stability diff --git a/mime.go b/mime.go new file mode 100644 index 0000000..2c11ebb --- /dev/null +++ b/mime.go @@ -0,0 +1,597 @@ +package muxie + +import ( + "mime" + "path/filepath" +) + +var types = map[string]string{ + ".3dm": "x-world/x-3dmf", + ".3dmf": "x-world/x-3dmf", + ".7z": "application/x-7z-compressed", + ".a": "application/octet-stream", + ".aab": "application/x-authorware-bin", + ".aam": "application/x-authorware-map", + ".aas": "application/x-authorware-seg", + ".abc": "text/vndabc", + ".ace": "application/x-ace-compressed", + ".acgi": "text/html", + ".afl": "video/animaflex", + ".ai": "application/postscript", + ".aif": "audio/aiff", + ".aifc": "audio/aiff", + ".aiff": "audio/aiff", + ".aim": "application/x-aim", + ".aip": "text/x-audiosoft-intra", + ".alz": "application/x-alz-compressed", + ".ani": "application/x-navi-animation", + ".aos": "application/x-nokia-9000-communicator-add-on-software", + ".aps": "application/mime", + ".apk": "application/vnd.android.package-archive", + ".arc": "application/x-arc-compressed", + ".arj": "application/arj", + ".art": "image/x-jg", + ".asf": "video/x-ms-asf", + ".asm": "text/x-asm", + ".asp": "text/asp", + ".asx": "application/x-mplayer2", + ".au": "audio/basic", + ".avi": "video/x-msvideo", + ".avs": "video/avs-video", + ".bcpio": "application/x-bcpio", + ".bin": "application/mac-binary", + ".bmp": "image/bmp", + ".boo": "application/book", + ".book": "application/book", + ".boz": "application/x-bzip2", + ".bsh": "application/x-bsh", + ".bz2": "application/x-bzip2", + ".bz": "application/x-bzip", + ".c++": "text/plain", + ".c": "text/x-c", + ".cab": "application/vnd.ms-cab-compressed", + ".cat": "application/vndms-pkiseccat", + ".cc": "text/x-c", + ".ccad": "application/clariscad", + ".cco": "application/x-cocoa", + ".cdf": "application/cdf", + ".cer": "application/pkix-cert", + ".cha": "application/x-chat", + ".chat": "application/x-chat", + ".chrt": "application/vnd.kde.kchart", + ".class": "application/java", + ".com": "text/plain", + ".conf": "text/plain", + ".cpio": "application/x-cpio", + ".cpp": "text/x-c", + ".cpt": "application/mac-compactpro", + ".crl": "application/pkcs-crl", + ".crt": "application/pkix-cert", + ".crx": "application/x-chrome-extension", + ".csh": "text/x-scriptcsh", + ".css": "text/css", + ".csv": "text/csv", + ".cxx": "text/plain", + ".dar": "application/x-dar", + ".dcr": "application/x-director", + ".deb": "application/x-debian-package", + ".deepv": "application/x-deepv", + ".def": "text/plain", + ".der": "application/x-x509-ca-cert", + ".dif": "video/x-dv", + ".dir": "application/x-director", + ".divx": "video/divx", + ".dl": "video/dl", + ".dmg": "application/x-apple-diskimage", + ".doc": "application/msword", + ".dot": "application/msword", + ".dp": "application/commonground", + ".drw": "application/drafting", + ".dump": "application/octet-stream", + ".dv": "video/x-dv", + ".dvi": "application/x-dvi", + ".dwf": "drawing/x-dwf=(old)", + ".dwg": "application/acad", + ".dxf": "application/dxf", + ".dxr": "application/x-director", + ".el": "text/x-scriptelisp", + ".elc": "application/x-bytecodeelisp=(compiled=elisp)", + ".eml": "message/rfc822", + ".env": "application/x-envoy", + ".eps": "application/postscript", + ".es": "application/x-esrehber", + ".etx": "text/x-setext", + ".evy": "application/envoy", + ".exe": "application/octet-stream", + ".f77": "text/x-fortran", + ".f90": "text/x-fortran", + ".f": "text/x-fortran", + ".fdf": "application/vndfdf", + ".fif": "application/fractals", + ".fli": "video/fli", + ".flo": "image/florian", + ".flv": "video/x-flv", + ".flx": "text/vndfmiflexstor", + ".fmf": "video/x-atomic3d-feature", + ".for": "text/x-fortran", + ".fpx": "image/vndfpx", + ".frl": "application/freeloader", + ".funk": "audio/make", + ".g3": "image/g3fax", + ".g": "text/plain", + ".gif": "image/gif", + ".gl": "video/gl", + ".gsd": "audio/x-gsm", + ".gsm": "audio/x-gsm", + ".gsp": "application/x-gsp", + ".gss": "application/x-gss", + ".gtar": "application/x-gtar", + ".gz": "application/x-compressed", + ".gzip": "application/x-gzip", + ".h": "text/x-h", + ".hdf": "application/x-hdf", + ".help": "application/x-helpfile", + ".hgl": "application/vndhp-hpgl", + ".hh": "text/x-h", + ".hlb": "text/x-script", + ".hlp": "application/hlp", + ".hpg": "application/vndhp-hpgl", + ".hpgl": "application/vndhp-hpgl", + ".hqx": "application/binhex", + ".hta": "application/hta", + ".htc": "text/x-component", + ".htm": "text/html", + ".html": "text/html", + ".htmls": "text/html", + ".htt": "text/webviewhtml", + ".htx": "text/html", + ".ice": "x-conference/x-cooltalk", + ".ico": "image/x-icon", + ".ics": "text/calendar", + ".icz": "text/calendar", + ".idc": "text/plain", + ".ief": "image/ief", + ".iefs": "image/ief", + ".iges": "application/iges", + ".igs": "application/iges", + ".ima": "application/x-ima", + ".imap": "application/x-httpd-imap", + ".inf": "application/inf", + ".ins": "application/x-internett-signup", + ".ip": "application/x-ip2", + ".isu": "video/x-isvideo", + ".it": "audio/it", + ".iv": "application/x-inventor", + ".ivr": "i-world/i-vrml", + ".ivy": "application/x-livescreen", + ".jam": "audio/x-jam", + ".jav": "text/x-java-source", + ".java": "text/x-java-source", + ".jcm": "application/x-java-commerce", + ".jfif-tbnl": "image/jpeg", + ".jfif": "image/jpeg", + ".jnlp": "application/x-java-jnlp-file", + ".jpe": "image/jpeg", + ".jpeg": "image/jpeg", + ".jpg": "image/jpeg", + ".jps": "image/x-jps", + ".js": "application/javascript", + ".json": "application/json", + ".jut": "image/jutvision", + ".kar": "audio/midi", + ".karbon": "application/vnd.kde.karbon", + ".kfo": "application/vnd.kde.kformula", + ".flw": "application/vnd.kde.kivio", + ".kml": "application/vnd.google-earth.kml+xml", + ".kmz": "application/vnd.google-earth.kmz", + ".kon": "application/vnd.kde.kontour", + ".kpr": "application/vnd.kde.kpresenter", + ".kpt": "application/vnd.kde.kpresenter", + ".ksp": "application/vnd.kde.kspread", + ".kwd": "application/vnd.kde.kword", + ".kwt": "application/vnd.kde.kword", + ".ksh": "text/x-scriptksh", + ".la": "audio/nspaudio", + ".lam": "audio/x-liveaudio", + ".latex": "application/x-latex", + ".lha": "application/lha", + ".lhx": "application/octet-stream", + ".list": "text/plain", + ".lma": "audio/nspaudio", + ".log": "text/plain", + ".lsp": "text/x-scriptlisp", + ".lst": "text/plain", + ".lsx": "text/x-la-asf", + ".ltx": "application/x-latex", + ".lzh": "application/octet-stream", + ".lzx": "application/lzx", + ".m1v": "video/mpeg", + ".m2a": "audio/mpeg", + ".m2v": "video/mpeg", + ".m3u": "audio/x-mpegurl", + ".m": "text/x-m", + ".man": "application/x-troff-man", + ".manifest": "text/cache-manifest", + ".map": "application/x-navimap", + ".mar": "text/plain", + ".mbd": "application/mbedlet", + ".mc$": "application/x-magic-cap-package-10", + ".mcd": "application/mcad", + ".mcf": "text/mcf", + ".mcp": "application/netmc", + ".me": "application/x-troff-me", + ".mht": "message/rfc822", + ".mhtml": "message/rfc822", + ".mid": "application/x-midi", + ".midi": "application/x-midi", + ".mif": "application/x-frame", + ".mime": "message/rfc822", + ".mjf": "audio/x-vndaudioexplosionmjuicemediafile", + ".mjpg": "video/x-motion-jpeg", + ".mm": "application/base64", + ".mme": "application/base64", + ".mod": "audio/mod", + ".moov": "video/quicktime", + ".mov": "video/quicktime", + ".movie": "video/x-sgi-movie", + ".mp2": "audio/mpeg", + ".mp3": "audio/mpeg", + ".mp4": "video/mp4", + ".mpa": "audio/mpeg", + ".mpc": "application/x-project", + ".mpe": "video/mpeg", + ".mpeg": "video/mpeg", + ".mpg": "video/mpeg", + ".mpga": "audio/mpeg", + ".mpp": "application/vndms-project", + ".mpt": "application/x-project", + ".mpv": "application/x-project", + ".mpx": "application/x-project", + ".mrc": "application/marc", + ".ms": "application/x-troff-ms", + ".mv": "video/x-sgi-movie", + ".my": "audio/make", + ".mzz": "application/x-vndaudioexplosionmzz", + ".nap": "image/naplps", + ".naplps": "image/naplps", + ".nc": "application/x-netcdf", + ".ncm": "application/vndnokiaconfiguration-message", + ".nif": "image/x-niff", + ".niff": "image/x-niff", + ".nix": "application/x-mix-transfer", + ".nsc": "application/x-conference", + ".nvd": "application/x-navidoc", + ".o": "application/octet-stream", + ".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", + ".oga": "audio/ogg", + ".ogg": "audio/ogg", + ".ogv": "video/ogg", + ".omc": "application/x-omc", + ".omcd": "application/x-omcdatamaker", + ".omcr": "application/x-omcregerator", + ".otc": "application/vnd.oasis.opendocument.chart-template", + ".otf": "application/vnd.oasis.opendocument.formula-template", + ".otg": "application/vnd.oasis.opendocument.graphics-template", + ".oth": "application/vnd.oasis.opendocument.text-web", + ".oti": "application/vnd.oasis.opendocument.image-template", + ".otm": "application/vnd.oasis.opendocument.text-master", + ".otp": "application/vnd.oasis.opendocument.presentation-template", + ".ots": "application/vnd.oasis.opendocument.spreadsheet-template", + ".ott": "application/vnd.oasis.opendocument.text-template", + ".p10": "application/pkcs10", + ".p12": "application/pkcs-12", + ".p7a": "application/x-pkcs7-signature", + ".p7c": "application/pkcs7-mime", + ".p7m": "application/pkcs7-mime", + ".p7r": "application/x-pkcs7-certreqresp", + ".p7s": "application/pkcs7-signature", + ".p": "text/x-pascal", + ".part": "application/pro_eng", + ".pas": "text/pascal", + ".pbm": "image/x-portable-bitmap", + ".pcl": "application/vndhp-pcl", + ".pct": "image/x-pict", + ".pcx": "image/x-pcx", + ".pdb": "chemical/x-pdb", + ".pdf": "application/pdf", + ".pfunk": "audio/make", + ".pgm": "image/x-portable-graymap", + ".pic": "image/pict", + ".pict": "image/pict", + ".pkg": "application/x-newton-compatible-pkg", + ".pko": "application/vndms-pkipko", + ".pl": "text/x-scriptperl", + ".plx": "application/x-pixclscript", + ".pm4": "application/x-pagemaker", + ".pm5": "application/x-pagemaker", + ".pm": "text/x-scriptperl-module", + ".png": "image/png", + ".pnm": "application/x-portable-anymap", + ".pot": "application/mspowerpoint", + ".pov": "model/x-pov", + ".ppa": "application/vndms-powerpoint", + ".ppm": "image/x-portable-pixmap", + ".pps": "application/mspowerpoint", + ".ppt": "application/mspowerpoint", + ".ppz": "application/mspowerpoint", + ".pre": "application/x-freelance", + ".prt": "application/pro_eng", + ".ps": "application/postscript", + ".psd": "application/octet-stream", + ".pvu": "paleovu/x-pv", + ".pwz": "application/vndms-powerpoint", + ".py": "text/x-scriptphyton", + ".pyc": "application/x-bytecodepython", + ".qcp": "audio/vndqcelp", + ".qd3": "x-world/x-3dmf", + ".qd3d": "x-world/x-3dmf", + ".qif": "image/x-quicktime", + ".qt": "video/quicktime", + ".qtc": "video/x-qtc", + ".qti": "image/x-quicktime", + ".qtif": "image/x-quicktime", + ".ra": "audio/x-pn-realaudio", + ".ram": "audio/x-pn-realaudio", + ".rar": "application/x-rar-compressed", + ".ras": "application/x-cmu-raster", + ".rast": "image/cmu-raster", + ".rexx": "text/x-scriptrexx", + ".rf": "image/vndrn-realflash", + ".rgb": "image/x-rgb", + ".rm": "application/vndrn-realmedia", + ".rmi": "audio/mid", + ".rmm": "audio/x-pn-realaudio", + ".rmp": "audio/x-pn-realaudio", + ".rng": "application/ringing-tones", + ".rnx": "application/vndrn-realplayer", + ".roff": "application/x-troff", + ".rp": "image/vndrn-realpix", + ".rpm": "audio/x-pn-realaudio-plugin", + ".rt": "text/vndrn-realtext", + ".rtf": "text/richtext", + ".rtx": "text/richtext", + ".rv": "video/vndrn-realvideo", + ".s": "text/x-asm", + ".s3m": "audio/s3m", + ".s7z": "application/x-7z-compressed", + ".saveme": "application/octet-stream", + ".sbk": "application/x-tbook", + ".scm": "text/x-scriptscheme", + ".sdml": "text/plain", + ".sdp": "application/sdp", + ".sdr": "application/sounder", + ".sea": "application/sea", + ".set": "application/set", + ".sgm": "text/x-sgml", + ".sgml": "text/x-sgml", + ".sh": "text/x-scriptsh", + ".shar": "application/x-bsh", + ".shtml": "text/x-server-parsed-html", + ".sid": "audio/x-psid", + ".skd": "application/x-koan", + ".skm": "application/x-koan", + ".skp": "application/x-koan", + ".skt": "application/x-koan", + ".sit": "application/x-stuffit", + ".sitx": "application/x-stuffitx", + ".sl": "application/x-seelogo", + ".smi": "application/smil", + ".smil": "application/smil", + ".snd": "audio/basic", + ".sol": "application/solids", + ".spc": "text/x-speech", + ".spl": "application/futuresplash", + ".spr": "application/x-sprite", + ".sprite": "application/x-sprite", + ".spx": "audio/ogg", + ".src": "application/x-wais-source", + ".ssi": "text/x-server-parsed-html", + ".ssm": "application/streamingmedia", + ".sst": "application/vndms-pkicertstore", + ".step": "application/step", + ".stl": "application/sla", + ".stp": "application/step", + ".sv4cpio": "application/x-sv4cpio", + ".sv4crc": "application/x-sv4crc", + ".svf": "image/vnddwg", + ".svg": "image/svg+xml", + ".svr": "application/x-world", + ".swf": "application/x-shockwave-flash", + ".t": "application/x-troff", + ".talk": "text/x-speech", + ".tar": "application/x-tar", + ".tbk": "application/toolbook", + ".tcl": "text/x-scripttcl", + ".tcsh": "text/x-scripttcsh", + ".tex": "application/x-tex", + ".texi": "application/x-texinfo", + ".texinfo": "application/x-texinfo", + ".text": "text/plain", + ".tgz": "application/gnutar", + ".tif": "image/tiff", + ".tiff": "image/tiff", + ".tr": "application/x-troff", + ".tsi": "audio/tsp-audio", + ".tsp": "application/dsptype", + ".tsv": "text/tab-separated-values", + ".turbot": "image/florian", + ".txt": "text/plain", + ".uil": "text/x-uil", + ".uni": "text/uri-list", + ".unis": "text/uri-list", + ".unv": "application/i-deas", + ".uri": "text/uri-list", + ".uris": "text/uri-list", + ".ustar": "application/x-ustar", + ".uu": "text/x-uuencode", + ".uue": "text/x-uuencode", + ".vcd": "application/x-cdlink", + ".vcf": "text/x-vcard", + ".vcard": "text/x-vcard", + ".vcs": "text/x-vcalendar", + ".vda": "application/vda", + ".vdo": "video/vdo", + ".vew": "application/groupwise", + ".viv": "video/vivo", + ".vivo": "video/vivo", + ".vmd": "application/vocaltec-media-desc", + ".vmf": "application/vocaltec-media-file", + ".voc": "audio/voc", + ".vos": "video/vosaic", + ".vox": "audio/voxware", + ".vqe": "audio/x-twinvq-plugin", + ".vqf": "audio/x-twinvq", + ".vql": "audio/x-twinvq-plugin", + ".vrml": "application/x-vrml", + ".vrt": "x-world/x-vrt", + ".vsd": "application/x-visio", + ".vst": "application/x-visio", + ".vsw": "application/x-visio", + ".w60": "application/wordperfect60", + ".w61": "application/wordperfect61", + ".w6w": "application/msword", + ".wav": "audio/wav", + ".wb1": "application/x-qpro", + ".wbmp": "image/vnd.wap.wbmp", + ".web": "application/vndxara", + ".wiz": "application/msword", + ".wk1": "application/x-123", + ".wmf": "windows/metafile", + ".wml": "text/vnd.wap.wml", + ".wmlc": "application/vnd.wap.wmlc", + ".wmls": "text/vnd.wap.wmlscript", + ".wmlsc": "application/vnd.wap.wmlscriptc", + ".word": "application/msword", + ".wp5": "application/wordperfect", + ".wp6": "application/wordperfect", + ".wp": "application/wordperfect", + ".wpd": "application/wordperfect", + ".wq1": "application/x-lotus", + ".wri": "application/mswrite", + ".wrl": "application/x-world", + ".wrz": "model/vrml", + ".wsc": "text/scriplet", + ".wsrc": "application/x-wais-source", + ".wtk": "application/x-wintalk", + ".x-png": "image/png", + ".xbm": "image/x-xbitmap", + ".xdr": "video/x-amt-demorun", + ".xgz": "xgl/drawing", + ".xif": "image/vndxiff", + ".xl": "application/excel", + ".xla": "application/excel", + ".xlb": "application/excel", + ".xlc": "application/excel", + ".xld": "application/excel", + ".xlk": "application/excel", + ".xll": "application/excel", + ".xlm": "application/excel", + ".xls": "application/excel", + ".xlt": "application/excel", + ".xlv": "application/excel", + ".xlw": "application/excel", + ".xm": "audio/xm", + ".xml": "text/xml", + ".xmz": "xgl/movie", + ".xpix": "application/x-vndls-xpix", + ".xpm": "image/x-xpixmap", + ".xsr": "video/x-amt-showrun", + ".xwd": "image/x-xwd", + ".xyz": "chemical/x-pdb", + ".z": "application/x-compress", + ".zip": "application/zip", + ".zoo": "application/octet-stream", + ".zsh": "text/x-scriptzsh", + ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".docm": "application/vnd.ms-word.document.macroEnabled.12", + ".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template", + ".dotm": "application/vnd.ms-word.template.macroEnabled.12", + ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12", + ".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template", + ".xltm": "application/vnd.ms-excel.template.macroEnabled.12", + ".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12", + ".xlam": "application/vnd.ms-excel.addin.macroEnabled.12", + ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12", + ".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow", + ".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", + ".potx": "application/vnd.openxmlformats-officedocument.presentationml.template", + ".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12", + ".ppam": "application/vnd.ms-powerpoint.addin.macroEnabled.12", + ".sldx": "application/vnd.openxmlformats-officedocument.presentationml.slide", + ".sldm": "application/vnd.ms-powerpoint.slide.macroEnabled.12", + ".thmx": "application/vnd.ms-officetheme", + ".onetoc": "application/onenote", + ".onetoc2": "application/onenote", + ".onetmp": "application/onenote", + ".onepkg": "application/onenote", + ".xpi": "application/x-xpinstall", + ".wasm": "application/wasm", +} + +func init() { + for ext, typ := range types { + // skip errors + mime.AddExtensionType(ext, typ) + } +} + +// TypeByExtension returns the MIME type associated with the file extension ext. +// The extension ext should begin with a leading dot, as in ".html". +// When ext has no associated type, typeByExtension returns "". +// +// Extensions are looked up first case-sensitively, then case-insensitively. +// +// The built-in table is small but on unix it is augmented by the local +// system's mime.types file(s) if available under one or more of these +// names: +// +// /etc/mime.types +// /etc/apache2/mime.types +// /etc/apache/mime.types +// +// On Windows, MIME types are extracted from the registry. +// +// Text types have the charset parameter set to "utf-8" by default. +func TypeByExtension(ext string) (typ string) { + if len(ext) < 2 { + return + } + + if ext[0] != '.' { // try to take it by filename + typ = TypeByFilename(ext) + if typ == "" { + ext = "." + ext // if error or something wrong then prepend the dot + } + } + + if typ == "" { + typ = mime.TypeByExtension(ext) + } + + // mime.TypeByExtension returns as text/plain; | charset=utf-8 the static .js (not always) + if ext == ".js" && (typ == "text/plain" || typ == "text/plain; charset=utf-8") { + + if ext == ".js" { + typ = "application/javascript" + } + } + return typ +} + +// TypeByFilename same as TypeByExtension +// but receives a filename path instead. +func TypeByFilename(fullFilename string) string { + ext := filepath.Ext(fullFilename) + return TypeByExtension(ext) +} diff --git a/node.go b/node.go index 28ea810..f21896b 100644 --- a/node.go +++ b/node.go @@ -52,7 +52,7 @@ func (n *Node) addChild(s string, child *Node) { func (n *Node) getChild(s string) *Node { if n.children == nil { - n.children = make(map[string]*Node) + return nil } return n.children[s] diff --git a/trie.go b/trie.go index 321139b..7c1f675 100644 --- a/trie.go +++ b/trie.go @@ -26,6 +26,8 @@ type Trie struct { // if true then it will handle any path if not other parent wildcard exists, // so even 404 (on http services) is up to it, see Trie#Insert. hasRootWildcard bool + + hasRootSlash bool } // NewTrie returns a new, empty Trie. @@ -120,6 +122,10 @@ func (t *Trie) insert(key, tag string, optionalData interface{}, handler http.Ha input := slowPathSplit(key) n := t.root + if key == pathSep { + t.hasRootSlash = true + } + var paramKeys []string for _, s := range input { @@ -240,7 +246,15 @@ func (t *Trie) Search(q string, params ParamsSetter) *Node { end := len(q) if end == 0 || (end == 1 && q[0] == pathSepB) { - return t.root.getChild(pathSep) + // fixes only root wildcard but no / registered at. + if t.hasRootSlash { + return t.root.getChild(pathSep) + } else if t.hasRootWildcard { + // no need to going through setting parameters, this one has not but it is wildcard. + return t.root.getChild(WildcardParamStart) + } + + return nil } n := t.root From 920ec04bf8a1c27fd7e921cd880d0495f74e1861 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Tue, 23 Oct 2018 18:42:20 +0300 Subject: [PATCH 03/14] add third-party source benchmarks links --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index ca3b9d2..230be43 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,14 @@ _Last updated on October 17, 2018._ Click [here](_benchmarks/README.md) to read more details. +### Third-party source benchmarks + +[![](https://github.com/kataras/iris/raw/master/_benchmarks/benchmarks_third_party_source_snapshot_go_23_october_2018.png)](https://github.com/the-benchmarker/web-frameworks#full-table) + +As shown in the benchmarks (from a [third-party source](https://github.com/the-benchmarker)), Muxie is much faster than its alternatives out there with amazing performance, fastest net/http router ever created so far. View the results and read further details [here](https://github.com/the-benchmarker/web-frameworks/tree/934fdf16e13a1a922ee88e873ae76f28f52c189f#full-table). + +_Last updated on October 23, 2018._ + ## Features - __trie based:__ [performance](_benchmarks/README.md) and useness are first class citizens, Muxie is based on the prefix tree data structure, designed from scratch and built for HTTP, and it is among the fastest outhere, if not the fastest one From 872076149a55f5755e453a3a9d6192b3b94b3db1 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Thu, 15 Nov 2018 20:24:37 +0200 Subject: [PATCH 04/14] add Mux#AbsPath to return the current SubMux path starting from root --- README.md | 2 +- _examples/10_fileserver/main.go | 16 ++++++++++++++++ _examples/10_fileserver/static/css/main.css | 7 +++++++ _examples/10_fileserver/static/index.html | 5 +++++ _examples/10_fileserver/static/js/empty.js | 1 + mux.go | 9 +++++++++ 6 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 _examples/10_fileserver/main.go create mode 100644 _examples/10_fileserver/static/css/main.css create mode 100644 _examples/10_fileserver/static/index.html create mode 100644 _examples/10_fileserver/static/js/empty.js diff --git a/README.md b/README.md index 230be43..7bb16bf 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@
- Release/stability diff --git a/_examples/10_fileserver/main.go b/_examples/10_fileserver/main.go new file mode 100644 index 0000000..0409832 --- /dev/null +++ b/_examples/10_fileserver/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "log" + "net/http" + + "github.com/kataras/muxie" +) + +func main() { + mux := muxie.NewMux() + mux.Handle("/static/*file", http.StripPrefix("/static/", http.FileServer(http.Dir("./static")))) + + log.Println("Server started at http://localhost:8080\nGET: http://localhost:8080/static/\nGET: http://localhost:8080/static/js/empty.js") + http.ListenAndServe(":8080", mux) +} diff --git a/_examples/10_fileserver/static/css/main.css b/_examples/10_fileserver/static/css/main.css new file mode 100644 index 0000000..0bc0596 --- /dev/null +++ b/_examples/10_fileserver/static/css/main.css @@ -0,0 +1,7 @@ +body { + background-color: black; +} + +h1 { + color: white; +} \ No newline at end of file diff --git a/_examples/10_fileserver/static/index.html b/_examples/10_fileserver/static/index.html new file mode 100644 index 0000000..3f964c6 --- /dev/null +++ b/_examples/10_fileserver/static/index.html @@ -0,0 +1,5 @@ +Index + +

Hello index

+ + \ No newline at end of file diff --git a/_examples/10_fileserver/static/js/empty.js b/_examples/10_fileserver/static/js/empty.js new file mode 100644 index 0000000..33af502 --- /dev/null +++ b/_examples/10_fileserver/static/js/empty.js @@ -0,0 +1 @@ +/* empty js file */ \ No newline at end of file diff --git a/mux.go b/mux.go index 50930eb..eb09270 100644 --- a/mux.go +++ b/mux.go @@ -211,6 +211,7 @@ type SubMux interface { Use(middlewares ...Wrapper) Handle(pattern string, handler http.Handler) HandleFunc(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) + AbsPath() string } // Of returns a new Mux which its Handle and HandleFunc will register the path based on given "prefix", i.e: @@ -249,6 +250,14 @@ func (m *Mux) Of(prefix string) SubMux { } } +// AbsPath returns the absolute path of the router for this Mux group. +func (m *Mux) AbsPath() string { + if m.root == "" { + return "/" + } + return m.root +} + /* Notes: Four options to solve optionally "inherition" of parent's middlewares but dismissed: From 6146dc09abeb502f7fab6c14f58c228d4b141970 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Fri, 1 Feb 2019 13:59:29 +0200 Subject: [PATCH 05/14] version 1.0.7 with an exported muxie.ResponseWriter that end-devs can wrap to custom http response writers --- LICENSE | 2 +- README.md | 2 +- doc.go | 2 +- params_writer.go | 43 ++++++++++++++++++++++++++++++------------- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/LICENSE b/LICENSE index 7ef5f6d..a38ff5c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2018 Gerasimos Maropoulos +Copyright (c) 2018-2019 Gerasimos Maropoulos Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 7bb16bf..aab2090 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@
- Release/stability diff --git a/doc.go b/doc.go index 736c1e5..98443c4 100644 --- a/doc.go +++ b/doc.go @@ -5,7 +5,7 @@ Source code and other details for the project are available at GitHub: Current Version -1.0.4 +1.0.7 Installation diff --git a/params_writer.go b/params_writer.go index fe0d7d3..023eefc 100644 --- a/params_writer.go +++ b/params_writer.go @@ -11,31 +11,31 @@ import ( // then the `GetParam("name")` will return the value of "kataras". // If not associated value with that key is found then it will return an empty string. // -// The function will do its job only if the given "w" http.ResponseWriter interface is an `paramsWriter`. +// The function will do its job only if the given "w" http.ResponseWriter interface is an `ResponseWriter`. func GetParam(w http.ResponseWriter, key string) string { - if store, ok := w.(*paramsWriter); ok { + if store, ok := w.(ResponseWriter); ok { return store.Get(key) } return "" } -// GetParams returns all the available parameters based on the "w" http.ResponseWriter which should be a *paramsWriter. +// GetParams returns all the available parameters based on the "w" http.ResponseWriter which should be a ResponseWriter. // -// The function will do its job only if the given "w" http.ResponseWriter interface is an `paramsWriter`. +// The function will do its job only if the given "w" http.ResponseWriter interface is an `ResponseWriter`. func GetParams(w http.ResponseWriter) []ParamEntry { - if store, ok := w.(*paramsWriter); ok { - return store.params + if store, ok := w.(ResponseWriter); ok { + return store.GetAll() } return nil } -// SetParam sets manually a parameter to the "w" http.ResponseWriter which should be a *paramsWriter. +// SetParam sets manually a parameter to the "w" http.ResponseWriter which should be a ResponseWriter. // This is not commonly used by the end-developers, // unless sharing values(string messages only) between handlers is absolutely necessary. func SetParam(w http.ResponseWriter, key, value string) bool { - if store, ok := w.(*paramsWriter); ok { + if store, ok := w.(ResponseWriter); ok { store.Set(key, value) return true } @@ -43,17 +43,29 @@ func SetParam(w http.ResponseWriter, key, value string) bool { return false } -type paramsWriter struct { - http.ResponseWriter - params []ParamEntry -} - // ParamEntry holds the Key and the Value of a named path parameter. type ParamEntry struct { Key string Value string } +// ResponseWriter is the muxie's specific ResponseWriter to hold the path parameters. +// Usage: use this to cast a handler's `http.ResponseWriter` and pass it as an embedded parameter to custom response writer +// that will be passed to the next handler in the chain. +type ResponseWriter interface { + http.ResponseWriter + ParamsSetter + Get(string) string + GetAll() []ParamEntry +} + +type paramsWriter struct { + http.ResponseWriter + params []ParamEntry +} + +var _ ResponseWriter = (*paramsWriter)(nil) + // Set implements the `ParamsSetter` which `Trie#Search` needs to store the parameters, if any. // These are decoupled because end-developers may want to use the trie to design a new Mux of their own // or to store different kind of data inside it. @@ -84,6 +96,11 @@ func (pw *paramsWriter) Get(key string) string { return "" } +// GetAll returns all the path parameters keys-values. +func (pw *paramsWriter) GetAll() []ParamEntry { + return pw.params +} + func (pw *paramsWriter) reset(w http.ResponseWriter) { pw.ResponseWriter = w pw.params = pw.params[0:0] From e00a33773d76eb319374dd4889798b9b6a6981c3 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Fri, 1 Feb 2019 14:00:55 +0200 Subject: [PATCH 06/14] version 1.0.7 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aab2090..3680071 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ - Build Status @@ -34,7 +34,7 @@ alt="Report Card" /> - + Example From 26471c2d07534584aa42c7f6d4a4372f89641929 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Mon, 8 Apr 2019 07:26:15 +0300 Subject: [PATCH 07/14] README addition --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index aab2090..0fe342a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Fast trie implementation designed from scratch specifically for HTTP
- A small and light router for creating sturdy backend Go applications + A small and light router for creating sturdy backend Go applications. Production-level tested, muxie's capabilities live inside the well-tested Iris web framework.

@@ -54,14 +54,6 @@ _Last updated on October 17, 2018._ Click [here](_benchmarks/README.md) to read more details. -### Third-party source benchmarks - -[![](https://github.com/kataras/iris/raw/master/_benchmarks/benchmarks_third_party_source_snapshot_go_23_october_2018.png)](https://github.com/the-benchmarker/web-frameworks#full-table) - -As shown in the benchmarks (from a [third-party source](https://github.com/the-benchmarker)), Muxie is much faster than its alternatives out there with amazing performance, fastest net/http router ever created so far. View the results and read further details [here](https://github.com/the-benchmarker/web-frameworks/tree/934fdf16e13a1a922ee88e873ae76f28f52c189f#full-table). - -_Last updated on October 23, 2018._ - ## Features - __trie based:__ [performance](_benchmarks/README.md) and useness are first class citizens, Muxie is based on the prefix tree data structure, designed from scratch and built for HTTP, and it is among the fastest outhere, if not the fastest one From df8dd6b276699465e7a360e88f18e094c1c831da Mon Sep 17 00:00:00 2001 From: fossabot Date: Sun, 14 Apr 2019 11:12:07 -0700 Subject: [PATCH 08/14] Add license scan report and status Signed-off-by: fossabot --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fe342a..685915e 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@
[![Benchmark chart between muxie, httprouter, gin, gorilla mux, echo, vestigo and chi](_benchmarks/chart-17-oct-2018.png)](_benchmarks) +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fkataras%2Fmuxie.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Fmuxie?ref=badge_shield) _Last updated on October 17, 2018._ Click [here](_benchmarks/README.md) to read more details. @@ -120,4 +121,6 @@ Gerasimos Maropoulos ([@MakisMaropoulos](https://twitter.com/MakisMaropoulos)) ## License -[MIT](https://tldrlegal.com/license/mit-license) \ No newline at end of file +[MIT](https://tldrlegal.com/license/mit-license) + +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fkataras%2Fmuxie.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fkataras%2Fmuxie?ref=badge_large) \ No newline at end of file From 2a0c1e8fdf480c5a64636726e10102024bb54eec Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Thu, 9 May 2019 15:10:59 +0300 Subject: [PATCH 09/14] fix readme example link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 685915e..50d19d5 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ _Last updated on October 17, 2018._ Click [here](_benchmarks/README.md) to read ## Technical Features -- [x] Closest Wildcard Resolution and Root wildcard (CWR)[*](_examples/3_root_wildcard_and_custom-404/main.go) +- [x] Closest Wildcard Resolution and Root wildcard (CWR)[*](_examples/3_root_wildcard_and_custom_404/main.go) - [x] Parameterized Dynamic Path (named parameters with `:name` and wildcards with `*name`, can play all together for the same path prefix|suffix)[*](_examples/2_parameterized/main.go) - [x] Standard handlers chain (`Pre(handlers).For(mainHandler)` for individual routes and `Mux#Use` for router)[*](_examples/6_middleware/main.go) - [x] Register handlers by method(s) (`muxie.Methods()`)[*](_examples/7_by_methods/main.go) From 6e55f24789eae87393deb8a0faf603482ad45f86 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Thu, 27 Jun 2019 16:29:29 +0300 Subject: [PATCH 10/14] minor --- mux.go | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/mux.go b/mux.go index eb09270..89c306a 100644 --- a/mux.go +++ b/mux.go @@ -1,8 +1,6 @@ package muxie import ( - "html" - "io" "net/http" "strings" "sync" @@ -63,7 +61,7 @@ func (m *Mux) AddRequestHandler(requestHandler RequestHandler) { m.requestHandlers = append(m.requestHandlers, requestHandler) } -// HandleRequest adds a matcher and a (conditinal) handler to be executed when "matcher" passed. +// HandleRequest adds a matcher and a (conditional) handler to be executed when "matcher" passed. // If the "matcher" passed then the "handler" will be executed // and this Mux' routes will be ignored. // @@ -168,14 +166,8 @@ func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, url, http.StatusTemporaryRedirect) return } - http.Redirect(w, r, url, http.StatusMovedPermanently) - // RFC2616 recommends that a short note "SHOULD" be included in the - // response because older user agents may not understand 301/307. - // Shouldn't send the response for POST or HEAD; that leaves GET. - if method == http.MethodGet { - io.WriteString(w, "Moved Permanently.\n") - } + http.Redirect(w, r, url, http.StatusMovedPermanently) return } } From 057f081060d194cdf520839b7c0bad2020506a7e Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Wed, 27 Nov 2019 00:50:16 +0200 Subject: [PATCH 11/14] internal: add more test options --- go.mod | 2 ++ mux_test.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index cf89ffd..58d2835 100644 --- a/go.mod +++ b/go.mod @@ -1 +1,3 @@ module github.com/kataras/muxie + +go 1.13 diff --git a/mux_test.go b/mux_test.go index 9b4141b..bfde40c 100644 --- a/mux_test.go +++ b/mux_test.go @@ -6,18 +6,51 @@ import ( "io/ioutil" "net/http" "net/http/httptest" + "net/url" + "strings" "testing" ) -func expect(t *testing.T, method, url string) *testie { +func expect(t *testing.T, method, url string, testieOptions ...func(*http.Request)) *testie { req, err := http.NewRequest(method, url, nil) if err != nil { t.Fatal(err) } + for _, opt := range testieOptions { + opt(req) + } + return testReq(t, req) } +func withHeader(key string, value string) func(*http.Request) { + return func(r *http.Request) { + r.Header.Add(key, value) + } +} + +func withURLParam(key string, value string) func(*http.Request) { + return func(r *http.Request) { + r.URL.Query().Add(key, value) + } +} + +func withFormField(key string, value string) func(*http.Request) { + return func(r *http.Request) { + if r.Form == nil { + r.Form = make(url.Values) + } + r.Form.Add(key, value) + + enc := strings.NewReader(r.Form.Encode()) + r.Body = ioutil.NopCloser(enc) + r.ContentLength = int64(enc.Len()) + + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + } +} + func expectWithBody(t *testing.T, method, url string, body string, headers http.Header) *testie { req, err := http.NewRequest(method, url, bytes.NewBufferString(body)) if err != nil { From ee2fdecdb9da73e99922508a6323aa8346f88ae6 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Thu, 5 Dec 2019 06:41:06 +0200 Subject: [PATCH 12/14] fix #8 --- README.md | 2 +- doc.go | 4 ++-- params_writer.go | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 50d19d5..c7e4cf2 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@
- Release/stability diff --git a/doc.go b/doc.go index 98443c4..b4dbce1 100644 --- a/doc.go +++ b/doc.go @@ -5,13 +5,13 @@ Source code and other details for the project are available at GitHub: Current Version -1.0.7 +1.0.8 Installation The only requirement is the Go Programming Language - $ go get -u github.com/kataras/muxie + $ go get github.com/kataras/muxie Examples diff --git a/params_writer.go b/params_writer.go index 023eefc..14fe932 100644 --- a/params_writer.go +++ b/params_writer.go @@ -105,3 +105,25 @@ func (pw *paramsWriter) reset(w http.ResponseWriter) { pw.ResponseWriter = w pw.params = pw.params[0:0] } + +// Flusher indicates if `Flush` is supported by the client. +// +// The default HTTP/1.x and HTTP/2 ResponseWriter implementations +// support Flusher, but ResponseWriter wrappers may not. Handlers +// should always test for this ability at runtime. +// +// Note that even for ResponseWriters that support Flush, +// if the client is connected through an HTTP proxy, +// the buffered data may not reach the client until the response +// completes. +func (pw *paramsWriter) Flusher() (http.Flusher, bool) { + flusher, canFlush := pw.ResponseWriter.(http.Flusher) + return flusher, canFlush +} + +// Flush sends any buffered data to the client. +func (pw *paramsWriter) Flush() { + if flusher, ok := pw.Flusher(); ok { + flusher.Flush() + } +} From 8179654e31a4c0764a73bab48c645cd63a1a8530 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Sun, 22 Dec 2019 17:02:14 +0200 Subject: [PATCH 13/14] Create FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..57f71e6 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: kataras From c9d5de314ec445b469a055640c349a1c06a15dfa Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Sat, 16 May 2020 07:23:26 +0300 Subject: [PATCH 14/14] add cors example and muxie.Methods().NoContent(http.MethodOptions) --- README.md | 6 ++--- _examples/11_cors/main.go | 46 +++++++++++++++++++++++++++++++++++++++ doc.go | 2 +- method_handler.go | 34 ++++++++++++++++++++++++++--- mux.go | 30 +++++++++++++++---------- 5 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 _examples/11_cors/main.go diff --git a/README.md b/README.md index c7e4cf2..4759e3a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@
- Release/stability @@ -84,7 +84,7 @@ The only requirement is the [Go Programming Language](https://golang.org/dl/) $ go get -u github.com/kataras/muxie ``` -## Philosophy + ## License diff --git a/_examples/11_cors/main.go b/_examples/11_cors/main.go new file mode 100644 index 0000000..d89727c --- /dev/null +++ b/_examples/11_cors/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "fmt" + "net/http" + + "github.com/kataras/muxie" +) + +func main() { + mux := muxie.NewMux() + mux.PathCorrection = true + + mux.Use(corsMiddleware) // <--- IMPORTANT: register the cors middleware. + + mux.Handle("/", muxie.Methods(). + NoContent(http.MethodOptions). // <--- IMPORTANT: cors preflight. + HandleFunc(http.MethodPost, postHandler)) + + fmt.Println("Server started at http://localhost:80") + http.ListenAndServe(":80", mux) +} + +func corsMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + h := w.Header() + h.Set("Access-Control-Allow-Origin", "*") + h.Set("Access-Control-Allow-Credentials", "true") + + if r.Method == http.MethodOptions { + h.Set("Access-Control-Methods", "POST, PUT, PATCH, DELETE") + h.Set("Access-Control-Allow-Headers", "Access-Control-Allow-Origin,Content-Type") + h.Set("Access-Control-Max-Age", "86400") + w.WriteHeader(http.StatusNoContent) + return + } + + next.ServeHTTP(w, r) + }) +} + +func postHandler(w http.ResponseWriter, r *http.Request) { + var request map[string]interface{} + muxie.JSON.Bind(r, &request) + muxie.JSON.Dispatch(w, map[string]string{"message": "ok"}) +} diff --git a/doc.go b/doc.go index b4dbce1..0d0ec37 100644 --- a/doc.go +++ b/doc.go @@ -5,7 +5,7 @@ Source code and other details for the project are available at GitHub: Current Version -1.0.8 +1.0.9 Installation diff --git a/method_handler.go b/method_handler.go index 2ad7b46..d96958c 100644 --- a/method_handler.go +++ b/method_handler.go @@ -29,12 +29,18 @@ func Methods() *MethodHandler { // 3. mux.Handle("/user/:id", muxie.Method("GET", getUserHandler).Method("POST", saveUserHandler)) // // 4. mux.Handle("/user/:id", muxie.Methods(). - // Handle("GET", getHandler). - // HandleFunc("POST", postHandler)) + // Handle("GET", getHandler). + // HandleFunc("POST", postHandler)) // return &MethodHandler{handlers: make(map[string]http.Handler)} } +// NoContentHandler defaults to a handler which just sends 204 status. +// See `MethodHandler.NoContent` method. +var NoContentHandler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) +}) + // MethodHandler implements the `http.Handler` which can be used on `Mux#Handle/HandleFunc` // to declare handlers responsible for specific HTTP method(s). // @@ -43,6 +49,12 @@ type MethodHandler struct { // origin *Mux handlers map[string]http.Handler // method:handler + // Handle/HandleFunc can accept more than one methods per handler separated by comma or space, + // however in order to not repeat ourselves for every handler: + // extra methods will be not registered to a handler but they can register + // the route so it can be reachable, it is binded to a handler which just sends status no content, + // can be used for OPTIONS on cors. + noContentMethods []string methodsAllowedStr string } @@ -67,7 +79,7 @@ func (m *MethodHandler) Handle(method string, handler http.Handler) *MethodHandl return m } - method = strings.ToUpper(strings.TrimSpace(method)) + method = normalizeMethod(method) if m.methodsAllowedStr == "" { m.methodsAllowedStr = method @@ -80,6 +92,18 @@ func (m *MethodHandler) Handle(method string, handler http.Handler) *MethodHandl return m } +// NoContent registers a handler to a method +// which sends 204 (no status content) to the client. +// +// Example: _examples/11_cors for more. +func (m *MethodHandler) NoContent(methods ...string) *MethodHandler { + for _, method := range methods { + m.handlers[normalizeMethod(method)] = NoContentHandler + } + + return m +} + // HandleFunc adds a handler function to be responsible for a specific HTTP Method. // Returns this MethodHandler for further calls. func (m *MethodHandler) HandleFunc(method string, handlerFunc func(w http.ResponseWriter, r *http.Request)) *MethodHandler { @@ -100,3 +124,7 @@ func (m *MethodHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Set("Allow", m.methodsAllowedStr) http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed) } + +func normalizeMethod(method string) string { + return strings.ToUpper(strings.TrimSpace(method)) +} diff --git a/mux.go b/mux.go index 89c306a..d1d3520 100644 --- a/mux.go +++ b/mux.go @@ -21,8 +21,14 @@ import ( // // See `NewMux`. type Mux struct { + // PathCorrection removes leading slashes from the request path. + // Defaults to false, however is highly recommended to turn it on. PathCorrection bool - Routes *Trie + // PathCorrectionNoRedirect if `PathCorrection` is set to true, + // it will execute the handlers chain without redirection. + // Defaults to false. + PathCorrectionNoRedirect bool + Routes *Trie paramsPool *sync.Pool @@ -157,18 +163,20 @@ func (m *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { // update the new path and redirect. // use Trim to ensure there is no open redirect due to two leading slashes r.URL.Path = pathSep + strings.Trim(path, pathSep) - url := r.URL.String() - method := r.Method - // Fixes https://github.com/kataras/iris/issues/921 - // This is caused for security reasons, imagine a payment shop, - // you can't just permantly redirect a POST request, so just 307 (RFC 7231, 6.4.7). - if method == http.MethodPost || method == http.MethodPut { - http.Redirect(w, r, url, http.StatusTemporaryRedirect) + if !m.PathCorrectionNoRedirect { + url := r.URL.String() + method := r.Method + // Fixes https://github.com/kataras/iris/issues/921 + // This is caused for security reasons, imagine a payment shop, + // you can't just permantly redirect a POST request, so just 307 (RFC 7231, 6.4.7). + if method == http.MethodPost || method == http.MethodPut { + http.Redirect(w, r, url, http.StatusTemporaryRedirect) + return + } + + http.Redirect(w, r, url, http.StatusMovedPermanently) return } - - http.Redirect(w, r, url, http.StatusMovedPermanently) - return } }