From ec9455da53887bdf184e14fcd036b5a392f025f8 Mon Sep 17 00:00:00 2001 From: Arthur Khachaturov Date: Fri, 26 Jul 2024 00:49:56 +0300 Subject: [PATCH] feat: markdown rendering --- src/constants.sh | 6 +- src/helpers.sh | 7 +- src/http_server.sh | 144 ++----- src/markdown.sh | 26 ++ src/mime.types | 985 +++++++++++++++++++++++++++++++++++++++++++++ src/request.sh | 41 ++ src/response.sh | 73 ++++ src/tcp_server.sh | 6 +- 8 files changed, 1170 insertions(+), 118 deletions(-) create mode 100644 src/markdown.sh create mode 100644 src/mime.types create mode 100644 src/request.sh create mode 100644 src/response.sh diff --git a/src/constants.sh b/src/constants.sh index 6d74044..99f7a86 100644 --- a/src/constants.sh +++ b/src/constants.sh @@ -1,5 +1,8 @@ # shellcheck disable=SC2034 # for now +[ -n "${HTTP_GUARD__CONSTANTS_SH+x}" ] && return +export HTTP_GUARD__CONSTANTS_SH='' + readonly HTTP_SERVER_VERSION='0.1.0' readonly HTTP_PROTOCOL_VERSION='HTTP/1.1' readonly HTTP_SERVER_STRING="httb/${HTTP_SERVER_VERSION}" @@ -69,6 +72,7 @@ declare -Ar HTTP_SUPPORTED_METHODS=( http::_status_code_page() { cat <<-EOF + ${1} ${HTTP_METHOD_NAMES["$1"]} @@ -78,5 +82,5 @@ http::_status_code_page() {
Server: ${HTTP_SERVER_STRING}
-EOF + EOF } diff --git a/src/helpers.sh b/src/helpers.sh index fe1d4f7..3b9051c 100644 --- a/src/helpers.sh +++ b/src/helpers.sh @@ -1,8 +1,11 @@ #!/bin/bash -# shellcheck disable=SC2015 + +[ -n "${HTTP_GUARD__HELPERS_SH+x}" ] && return +export HTTP_GUARD__HELPERS_SH='' http::_tempfile() { [ ! -d "/dev/shm" ] && TMP_FOLDER="/tmp" || TMP_FOLDER="/dev/shm" - [ ! -d "${TMP_FOLDER}/httb-server" ] && mkdir "${TMP_FOLDER}/httb-server" || + # shellcheck disable=SC2015 + [ ! -d "${TMP_FOLDER}/httb-server" ] && mkdir "${TMP_FOLDER}/httb-server" || mktemp -t 'httb-server.XXXXXXXXXXXX' -p "${TMP_FOLDER}/httb-server" } diff --git a/src/http_server.sh b/src/http_server.sh index e0b9f5a..2518127 100644 --- a/src/http_server.sh +++ b/src/http_server.sh @@ -1,22 +1,42 @@ #!/bin/bash -# shellcheck shell=bash set -e shopt -s globstar extglob dotglob -# shellcheck source-path=../ -HTTP_SCRIPT_PATH="$(dirname "$(readlink -e "${BASH_SOURCE[0]:-$0}")")" +[ -n "${HTTP_GUARD__HTTP_SERVER_SH+x}" ] && return +export HTTP_GUARD__HTTP_SERVER_SH='' + +: "${HTTP_SCRIPT_PATH:="$(dirname "$(readlink -e "${BASH_SOURCE[0]:-$0}")")"}" readonly HTTP_SCRIPT_PATH +# shellcheck source=./constants.sh . "${HTTP_SCRIPT_PATH}/constants.sh" +# shellcheck source=./helpers.sh . "${HTTP_SCRIPT_PATH}/helpers.sh" - +# shellcheck source=./request.sh +. "${HTTP_SCRIPT_PATH}/request.sh" +# shellcheck source=./response.sh +. "${HTTP_SCRIPT_PATH}/response.sh" +# shellcheck source=./markdown.sh +. "${HTTP_SCRIPT_PATH}/markdown.sh" declare -A http__handlers=() declare -A http__all_routes=() # -- CONFIGURATION -- +http::run() { + if [[ "$1" = "run" ]]; then + echo "Listening on ${HTTP_HOST:=${HTTP_DEFAULT_HOST}}:${HTTP_PORT:=${HTTP_DEFAULT_PORT}}" + socat "TCP-LISTEN:${HTTP_PORT},bind=${HTTP_HOST},fork,reuseport" "EXEC:$(readlink -e "$0") parse" + elif [[ "$1" = "parse" ]]; then + http::_process_request + else + http::_cmd_help >&2 + exit 1 + fi +} + http::host() { export HTTP_HOST_NAME="$1"; } http::bind() { export HTTP_HOST="${1:-${HTTP_DEFAULT_HOST}}"; export HTTP_PORT="${2:-${HTTP_DEFAULT_PORT}}"; } http::markdown_base() { export HTTP_MARKDOWN_BASE="$1"; } @@ -27,90 +47,20 @@ http::static_folder() { export HTTP_STATIC_FOLDER="$2"; } -# -- PUBLIC METHODS -- http::route() { local _method while read -r _method; do # temp until all methods are suppoorted [[ -z "${HTTP_SUPPORTED_METHODS["${_method}"]}" ]] && echo "$1: Method ${_method} not implemented!" >&2 && exit 1 - http__handlers["$_method,$3"]="$1" + http__handlers["$_method,$3"]="$1" # bad, skill issue http__all_routes["$3"]=1 done <<< "${2/ /$'\n'}" } + http::get() { http::route "$1" "GET" "$2"; } -# -- REQUEST PROCESSING -- - -http::_parse_headers() { - read -r request_method request_path request_version - - while read -r header_; do - [[ -z "${header_/$'\r'/}" ]] && break - local h_name h_value - IFS=: read -r h_name h_value <<< "${header_/': '/:}" - request_headers["${h_name}"]="${h_value}" - done -} - -http::_parse_body() { :; } # TODO - -http::_route_request() { - [[ -z "${HTTP_SUPPORTED_METHODS[${request_method}]}" ]] && http::response 501 && return 1 - local glob_endpoint handler path_found - - for glob_endpoint in "${!http__all_routes[@]}"; do # FIXME - # shellcheck disable=SC2053 - if [[ "${request_path}" == ${glob_endpoint} ]]; then - declare -rx HTTP_REQUEST_GLOB="${glob_endpoint}" - path_found=1 - break - fi - done - - handler="${http__handlers["$request_method,$glob_endpoint"]}" - - if [[ -z "${path_found}" ]]; then - http::response 404; return 1 - elif [[ -z "${handler}" ]]; then - http::response 405; return 1 - else - "${handler}" - fi -} - -# -- RESPONSE PROCESSING -- - -http::_response_base_headers() { - connection_string="${HTTP_PROTOCOL_VERSION} $1 ${HTTP_METHOD_NAMES["$1"]}" - response_headers["Server"]="${HTTP_SERVER_STRING}" - response_headers["Connection"]="close" - response_headers["Date"]="$(date -Ru)" - response_headers["Cache-control"]="no-cache" - response_headers["Cache-control"]="max-age=0" -} - -http::_set_response_content_type() { - response_headers["Content-Type"]="$(file -ib "$1")" -} - -# $1 = file with content $2 = filename -http::_response_content_headers() { - response_headers["Content-Length"]="$(wc -c "$1" | cut -d ' ' -f 1)" - [[ -z "${response_headers["Content-Type"]}" ]] && response_headers["Content-Type"]="$(file -ib "$1")" - echo -} - -http::_response_content() { - local -r content_file="$(http::_tempfile)" # TODO mb adapt to mkfifo pipes - cat - > "${content_file}" - - http::_response_content_headers "${content_file}" - - cat "${content_file}" - rm -f "${content_file}" -} http::_static_file() { local uri_path="${request_path#"${HTTP_REQUEST_GLOB%'**'}"}" @@ -119,33 +69,12 @@ http::_static_file() { http::file "${filename}" } -http::response() { - local status_code page - [[ -n "${HTTP_METHOD_NAMES["$1"]}" ]] && status_code="$1" || status_code="500" - page="$(http::_status_code_page "${status_code}")" - response_headers["Content-Type"]="text/html" - http::_response_base_headers "${status_code}" - http::_response_content <<< "${page}" -} - -http::file() { - [[ ! -f "$1" ]] && http::response 500 && return 1 - http::_response_base_headers "200" - http::_set_response_content_type "$1" - http::_response_content < "$1" -} - -http::html() { response_headers["Content-Type"]="text/html" http::file "$@"; } - -http::format_markdown() { :; } # TODO - -# -- COMMAND LINE LOGIC -- http::_process_request() { - declare -Ax request_headers response_headers - export request_method request_path request_version connection_string + local -A request_headers response_headers + local request_method request_path request_version connection_string - http::_parse_headers || { http::response 500 && return 0; } + http::_parse_headers || { http::response 405 && return 0; } # { [[ "${request_method}" != "GET" ]] && http::_parse_body; || { http::response 500 && return 0; } if [[ -n "${HTTP_HOST_NAME}" && "${HTTP_HOST_NAME}" != "${request_headers["Host"]%:*}" ]]; then @@ -153,8 +82,10 @@ http::_process_request() { return 0 fi + : "${request_version}" + http::_route_request - [[ -z "${connection_string}" ]] && http::response 500 && return 0 + [[ -z "${connection_string}" ]] && { http::response 500; return 0; } return 0 } @@ -168,14 +99,3 @@ http::_cmd_help() { echo " parse Parse http request from stdin and output to stdout" } -http::run() { - if [[ "$1" = "run" ]]; then - echo "Listening on ${HTTP_HOST:=${HTTP_DEFAULT_HOST}}:${HTTP_PORT:=${HTTP_DEFAULT_PORT}}" - socat "TCP-LISTEN:${HTTP_PORT},bind=${HTTP_HOST},fork,reuseport" "EXEC:$(readlink -e "$0") parse" - elif [[ "$1" = "parse" ]]; then - http::_process_request - else - http::_cmd_help >&2 - exit 1 - fi -} diff --git a/src/markdown.sh b/src/markdown.sh new file mode 100644 index 0000000..fc2eec0 --- /dev/null +++ b/src/markdown.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +[ -n "${HTTP_GUARD__MARKDOWN_SH+x}" ] && return +export HTTP_GUARD__MARKDOWN_SH='' + + +http::_convert_to_md() { + local -a pandoc_options=( + '--from=gfm+tex_math_dollars ' + '--to=html' + '--mathjax' + '--toc' + "--template=${HTTP_MARKDOWN_BASE:-'default.html5'}" + ) + pandoc "${pandoc_options[@]}" "$1" +} + +http::md() { + [[ ! -f "$1" ]] && { http::response 500 && return 1; } + markdown="$(http::_convert_to_md "$1")" + http::_response_base_headers "200" + response_headers["Content-Type"]="text/html" + http::_response_content_headers <(printf "%s" "$markdown") + http::_output_response_headers + printf "%s" "$markdown" +} diff --git a/src/mime.types b/src/mime.types new file mode 100644 index 0000000..2c61f57 --- /dev/null +++ b/src/mime.types @@ -0,0 +1,985 @@ +application/andrew-inset ez +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +application/atomsvc+xml atomsvc +application/ccxml+xml ccxml +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +application/cu-seeme cu +application/davmount+xml davmount +application/docbook+xml dbk +application/dssc+der dssc +application/dssc+xml xdssc +application/ecmascript ecma +application/emma+xml emma +application/epub+zip epub +application/exi exi +application/font-tdpfr pfr +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +application/hyperstudio stk +application/inkml+xml ink +application/inkml+xml inkml +application/ipfix ipfix +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/jsonml+json jsonml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma +application/mathematica nb +application/mathematica mb +application/mathml+xml mathml +application/mbox mbox +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +application/mods+xml mods +application/mp21 m21 +application/mp21 mp21 +application/mp4 mp4s +application/msword doc +application/msword dot +application/mxf mxf +application/octet-stream bin +application/octet-stream dms +application/octet-stream lrf +application/octet-stream mar +application/octet-stream so +application/octet-stream dist +application/octet-stream distz +application/octet-stream pkg +application/octet-stream bpk +application/octet-stream dump +application/octet-stream elc +application/octet-stream deploy +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onetoc +application/onenote onetoc2 +application/onenote onetmp +application/onenote onepkg +application/oxps oxps +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +application/pgp-signature asc +application/pgp-signature sig +application/pics-rules prf +application/pkcs10 p10 +application/pkcs7-mime p7m +application/pkcs7-mime p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +application/postscript ai +application/postscript eps +application/postscript ps +application/prs.cww cww +application/pskc+xml pskcxml +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +application/rls-services+xml rs +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +application/set-payment-initiation setpay +application/set-registration-initiation setreg +application/shf+xml shf +application/smil+xml smi +application/smil+xml smil +application/sparql-query rq +application/sparql-results+xml srx +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +application/tei+xml tei +application/tei+xml teicorpus +application/thraud+xml tfi +application/timestamped-data tsd +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc +application/vnd.acucorp acutc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp +application/vnd.adobe.fxp fxpl +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.mpegurl m3u8 +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +application/vnd.blueice.multipass mpm +application/vnd.bmi bmi +application/vnd.businessobjects rep +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g +application/vnd.clonk.c4group c4d +application/vnd.clonk.c4group c4f +application/vnd.clonk.c4group c4p +application/vnd.clonk.c4group c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +application/vnd.cups-ppd ppd +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dece.data uvf +application/vnd.dece.data uvvf +application/vnd.dece.data uvd +application/vnd.dece.data uvvd +application/vnd.dece.ttml+xml uvt +application/vnd.dece.ttml+xml uvvt +application/vnd.dece.unspecified uvx +application/vnd.dece.unspecified uvvx +application/vnd.dece.zip uvz +application/vnd.dece.zip uvvz +application/vnd.denovo.fcselayout-link fe_launch +application/vnd.dna dna +application/vnd.dolby.mlp mlp +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +application/vnd.dvb.service svc +application/vnd.dynageo geo +application/vnd.ecowin.chart mag +application/vnd.enliven nml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +application/vnd.eszigno3+xml es3 +application/vnd.eszigno3+xml et3 +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed seed +application/vnd.fdsn.seed dataless +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +application/vnd.framemaker fm +application/vnd.framemaker frame +application/vnd.framemaker maker +application/vnd.framemaker book +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex +application/vnd.geometry-explorer gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf +application/vnd.grafeq gqs +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +application/vnd.hydrostatix.sof-data sfd-hdstx +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp +application/vnd.ibm.modcap listafp +application/vnd.ibm.modcap list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc +application/vnd.iccprofile icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw +application/vnd.intercon.formnet xpx +application/vnd.intergeo i2g +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz +application/vnd.kahootz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr +application/vnd.kde.kpresenter kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd +application/vnd.kde.kword kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne +application/vnd.kinar knp +application/vnd.koan skp +application/vnd.koan skd +application/vnd.koan skt +application/vnd.koan skm +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xls +application/vnd.ms-excel xlm +application/vnd.ms-excel xla +application/vnd.ms-excel xlc +application/vnd.ms-excel xlt +application/vnd.ms-excel xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +application/vnd.ms-officetheme thmx +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +application/vnd.ms-powerpoint ppt +application/vnd.ms-powerpoint pps +application/vnd.ms-powerpoint pot +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +application/vnd.ms-project mpp +application/vnd.ms-project mpt +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wps +application/vnd.ms-works wks +application/vnd.ms-works wcm +application/vnd.ms-works wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf ntf +application/vnd.nitf nitf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.olpc-sugar xo +application/vnd.oma.dd2+xml dd2 +application/vnd.openofficeorg.extension oxt +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +application/vnd.openxmlformats-officedocument.presentationml.template potx +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +application/vnd.osgeo.mapguide.package mgp +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +application/vnd.palm pdb +application/vnd.palm pqa +application/vnd.palm oprc +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +application/vnd.picsel efif +application/vnd.pmi.widget wg +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +application/vnd.quark.quarkxpress qxd +application/vnd.quark.quarkxpress qxt +application/vnd.quark.quarkxpress qwd +application/vnd.quark.quarkxpress qwt +application/vnd.quark.quarkxpress qxl +application/vnd.quark.quarkxpress qxb +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +application/vnd.sailingtracker.track st +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd +application/vnd.simtech-mindmapper twds +application/vnd.smaf mmf +application/vnd.smart.teacher teacher +application/vnd.solent.sdkm+xml sdkm +application/vnd.solent.sdkm+xml sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw +application/vnd.stardivision.writer vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.sus-calendar sus +application/vnd.sus-calendar susp +application/vnd.svd svd +application/vnd.symbian.install sis +application/vnd.symbian.install sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap pcap +application/vnd.tcpdump.pcap cap +application/vnd.tcpdump.pcap dmp +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +application/vnd.ufdl ufd +application/vnd.ufdl ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +application/vnd.vcx vcx +application/vnd.visio vsd +application/vnd.visio vst +application/vnd.visio vss +application/vnd.visio vsw +application/vnd.visionary vis +application/vnd.vsf vsf +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +application/vnd.wt.stf stf +application/vnd.xara xar +application/vnd.xfdl xfdl +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir +application/vnd.zul zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +application/widget wgt +application/winhlp hlp +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +application/x-apple-diskimage dmg +application/x-authorware-bin aab +application/x-authorware-bin x32 +application/x-authorware-bin u32 +application/x-authorware-bin vox +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb +application/x-blorb blorb +application/x-bzip bz +application/x-bzip2 bz2 +application/x-bzip2 boz +application/x-cbr cbr +application/x-cbr cba +application/x-cbr cbt +application/x-cbr cbz +application/x-cbr cb7 +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-conference nsc +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb +application/x-debian-package udeb +application/x-dgc-compressed dgc +application/x-director dir +application/x-director dcr +application/x-director dxr +application/x-director cst +application/x-director cct +application/x-director cxt +application/x-director w3d +application/x-director fgd +application/x-director swa +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +application/x-font-ghostscript gsf +application/x-font-linux-psf psf +application/x-font-pcf pcf +application/x-font-snf snf +application/x-font-type1 pfa +application/x-font-type1 pfb +application/x-font-type1 pfm +application/x-font-type1 afm +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +application/x-hdf hdf +application/x-install-instructions install +application/x-iso9660-image iso +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-lzh-compressed lzh +application/x-lzh-compressed lha +application/x-mie mie +application/x-mobipocket-ebook prc +application/x-mobipocket-ebook mobi +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe +application/x-msdownload dll +application/x-msdownload com +application/x-msdownload bat +application/x-msdownload msi +application/x-msmediaview mvb +application/x-msmediaview m13 +application/x-msmediaview m14 +application/x-msmetafile wmf +application/x-msmetafile wmz +application/x-msmetafile emf +application/x-msmetafile emz +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc +application/x-netcdf cdf +application/x-nzb nzb +application/x-pkcs12 p12 +application/x-pkcs12 pfx +application/x-pkcs7-certificates p7b +application/x-pkcs7-certificates spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-research-info-systems ris +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo +application/x-texinfo texi +application/x-tgif obj +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der +application/x-x509-ca-cert crt +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 +application/x-zmachine z2 +application/x-zmachine z3 +application/x-zmachine z4 +application/x-zmachine z5 +application/x-zmachine z6 +application/x-zmachine z7 +application/x-zmachine z8 +application/xaml+xml xaml +application/xcap-diff+xml xdf +application/xenc+xml xenc +application/xhtml+xml xhtml +application/xhtml+xml xht +application/xml xml +application/xml xsl +application/xml-dtd dtd +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml +application/xv+xml xhvml +application/xv+xml xvml +application/xv+xml xvm +application/yang yang +application/yin+xml yin +application/zip zip +audio/adpcm adp +audio/basic au +audio/basic snd +audio/midi mid +audio/midi midi +audio/midi kar +audio/midi rmi +audio/mp4 m4a +audio/mp4 mp4a +audio/mpeg mpga +audio/mpeg mp2 +audio/mpeg mp2a +audio/mpeg mp3 +audio/mpeg m2a +audio/mpeg m3a +audio/ogg oga +audio/ogg ogg +audio/ogg spx +audio/s3m s3m +audio/silk sil +audio/vnd.dece.audio uva +audio/vnd.dece.audio uvva +audio/vnd.digital-winds eol +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +audio/vnd.rip rip +audio/webm weba +audio/x-aac aac +audio/x-aiff aif +audio/x-aiff aiff +audio/x-aiff aifc +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram +audio/x-pn-realaudio ra +audio/x-pn-realaudio-plugin rmp +audio/x-wav wav +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +chemical/x-xyz xyz +font/collection ttc +font/otf otf +font/ttf ttf +font/woff woff +font/woff2 woff2 +image/bmp bmp +image/cgm cgm +image/g3fax g3 +image/gif gif +image/ief ief +image/jpeg jpeg +image/jpeg jpg +image/jpeg jpe +image/ktx ktx +image/png png +image/prs.btif btif +image/sgi sgi +image/svg+xml svg +image/svg+xml svgz +image/tiff tiff +image/tiff tif +image/vnd.adobe.photoshop psd +image/vnd.dece.graphic uvi +image/vnd.dece.graphic uvvi +image/vnd.dece.graphic uvg +image/vnd.dece.graphic uvvg +image/vnd.djvu djvu +image/vnd.djvu djv +image/vnd.dvb.subtitle sub +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh +image/x-freehand fhc +image/x-freehand fh4 +image/x-freehand fh5 +image/x-freehand fh7 +image/x-icon ico +image/x-mrsid-image sid +image/x-pcx pcx +image/x-pict pic +image/x-pict pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/rfc822 eml +message/rfc822 mime +model/iges igs +model/iges iges +model/mesh msh +model/mesh mesh +model/mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +model/vnd.gdl gdl +model/vnd.gtw gtw +model/vnd.mts mts +model/vnd.vtu vtu +model/vrml wrl +model/vrml vrml +model/x3d+binary x3db +model/x3d+binary x3dbz +model/x3d+vrml x3dv +model/x3d+vrml x3dvz +model/x3d+xml x3d +model/x3d+xml x3dz +text/cache-manifest appcache +text/calendar ics +text/calendar ifb +text/css css +text/csv csv +text/html html +text/html htm +text/n3 n3 +text/plain txt +text/plain text +text/plain conf +text/plain def +text/plain list +text/plain log +text/plain in +text/prs.lines.tag dsc +text/richtext rtx +text/sgml sgml +text/sgml sgm +text/tab-separated-values tsv +text/troff t +text/troff tr +text/troff roff +text/troff man +text/troff me +text/troff ms +text/turtle ttl +text/uri-list uri +text/uri-list uris +text/uri-list urls +text/vcard vcard +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.mcurl mcurl +text/vnd.curl.scurl scurl +text/vnd.dvb.subtitle sub +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +text/vnd.sun.j2me.app-descriptor jad +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s +text/x-asm asm +text/x-c c +text/x-c cc +text/x-c cxx +text/x-c cpp +text/x-c h +text/x-c hh +text/x-c dic +text/x-fortran f +text/x-fortran for +text/x-fortran f77 +text/x-fortran f90 +text/x-java-source java +text/x-nfo nfo +text/x-opml opml +text/x-pascal p +text/x-pascal pas +text/x-setext etx +text/x-sfv sfv +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +video/3gpp 3gp +video/3gpp2 3g2 +video/h261 h261 +video/h263 h263 +video/h264 h264 +video/jpeg jpgv +video/jpm jpm +video/jpm jpgm +video/mj2 mj2 +video/mj2 mjp2 +video/mp4 mp4 +video/mp4 mp4v +video/mp4 mpg4 +video/mpeg mpeg +video/mpeg mpg +video/mpeg mpe +video/mpeg m1v +video/mpeg m2v +video/ogg ogv +video/quicktime qt +video/quicktime mov +video/vnd.dece.hd uvh +video/vnd.dece.hd uvvh +video/vnd.dece.mobile uvm +video/vnd.dece.mobile uvvm +video/vnd.dece.pd uvp +video/vnd.dece.pd uvvp +video/vnd.dece.sd uvs +video/vnd.dece.sd uvvs +video/vnd.dece.video uvv +video/vnd.dece.video uvvv +video/vnd.dvb.file dvb +video/vnd.fvt fvt +video/vnd.mpegurl mxu +video/vnd.mpegurl m4u +video/vnd.ms-playready.media.pyv pyv +video/vnd.uvvu.mp4 uvu +video/vnd.uvvu.mp4 uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mkv +video/x-matroska mk3d +video/x-matroska mks +video/x-mng mng +video/x-ms-asf asf +video/x-ms-asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice diff --git a/src/request.sh b/src/request.sh new file mode 100644 index 0000000..2a9ac37 --- /dev/null +++ b/src/request.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +[ -n "${HTTP_GUARD__REQUEST_SH+x}" ] && return +export HTTP_GUARD__REQUEST_SH='' + +http::_parse_headers() { + read -r request_method request_path request_version + + while read -r header_; do + [[ -z "${header_/$'\r'/}" ]] && break + local h_name h_value + IFS=: read -r h_name h_value <<< "${header_/': '/:}" + request_headers["${h_name}"]="${h_value}" + done +} + +http::_parse_body() { cat - >/dev/null; } # TODO + +http::_route_request() { + [[ -z "${HTTP_SUPPORTED_METHODS[${request_method}]}" ]] && http::response 501 && return 1 + local glob_endpoint handler path_found + + for glob_endpoint in "${!http__all_routes[@]}"; do # FIXME O(n) + # shellcheck disable=SC2053 + if [[ "${request_path}" == ${glob_endpoint} ]]; then + declare -rx HTTP_REQUEST_GLOB="${glob_endpoint}" + path_found=1 + break + fi + done + + handler="${http__handlers["$request_method,$glob_endpoint"]}" + + if [[ -z "${path_found}" ]]; then + http::response 404; return 1 + elif [[ -z "${handler}" ]]; then + http::response 405; return 1 + else + "${handler}" + fi +} diff --git a/src/response.sh b/src/response.sh new file mode 100644 index 0000000..12114b0 --- /dev/null +++ b/src/response.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +[ -n "${HTTP_GUARD__RESPONSE_SH+x}" ] && return +export HTTP_GUARD__RESPONSE_SH='' + +: "${HTTP_SCRIPT_PATH:="$(dirname "$(readlink -e "${BASH_SOURCE[0]:-$0}")")"}" +readonly HTTP_SCRIPT_PATH + +declare -A mime_types + +while IFS=' ' read -r type ext; do + mime_types["$ext"]="$type" +done < "$HTTP_SCRIPT_PATH/mime.types" + + +# $1 = status code +http::_response_base_headers() { + connection_string="${HTTP_PROTOCOL_VERSION} $1 ${HTTP_METHOD_NAMES["$1"]}" + : "${response_headers["Server"]:="${HTTP_SERVER_STRING}"}" + : "${response_headers["Connection"]:="close"}" + : "${response_headers["Date"]:="$(date -Ru)"}" + : "${response_headers["Cache-control"]:="no-cache"}" + : "${response_headers["Cache-control"]:="max-age=0"}" +} + + +# $1 = filename +http::_response_content_headers() { + local type ext + response_headers["Content-Length"]="$(wc -c "$1" | cut -d ' ' -f 1)" + + ext="$(cut -d '.' -f 2 <<< "$(basename "$1")")" + : "${response_headers["Content-Type"]:="${mime_types["$ext"]:-"$(file -ib "$1")"}"}" +} + + +http::_output_response_headers() { + echo "${connection_string}" + for header_name in "${!response_headers[@]}"; do + echo "${header_name}: ${response_headers[$header_name]}" + done + echo +} + + +# calle provides local -A response_headers +# $1 = status code +http::response() { + local status_code status_page + [[ -n "${HTTP_METHOD_NAMES["$1"]}" ]] && status_code="$1" || status_code="500" + status_page="$(http::_status_code_page "${status_code}")" + response_headers["Content-Type"]="text/html" + http::_response_base_headers "${status_code}" + http::_response_content_headers <(printf "%s" "${status_page}") + http::_output_response_headers + printf "%s" "${status_page}" +} + + +# calle provides local -A response_headers +# $1 = filename +http::file() { + [[ ! -f "$1" ]] && { http::response 500 && return 1; } + http::_response_base_headers "200" + http::_response_content_headers "$1" + http::_output_response_headers + cat "$1" +} + + +# calle provides local -A response_headers +# $1 = filename +http::html() { response_headers["Content-Type"]="text/html" http::file "$@"; } diff --git a/src/tcp_server.sh b/src/tcp_server.sh index 161c100..e4f0aa5 100644 --- a/src/tcp_server.sh +++ b/src/tcp_server.sh @@ -14,10 +14,10 @@ tcp::worker_() { exec {socket_output}<> <(:) # { nc -lknv -s "${host}" -p "${port}" > >( stdbuf -o0 sed "s/$delimiter/$delimiter_placeholder/g" ) 2> >( stdbuf -o0 sed "/Listening on.*/d;s/Connection received on /$delimiter/" >&2; ) ; } <&$socket_input >&$socket_output 2>&1 & - { + { socat "TCP-LISTEN:${host:-80},bind=${port:-127.0.0.1},fork,reuseport" \ > >( stdbuf -o0 sed "s/$delimiter/$delimiter_placeholder/g" ) \ - 2> >( stdbuf -o0 sed "/Listening on.*/d;s/Connection received on /$delimiter/" >&2; ) ; + 2> >( stdbuf -o0 sed "/Listening on.*/d;s/Connection received on /$delimiter/" >&2; ) ; } <&$socket_input >&$socket_output 2>&1 & echo "listenning" @@ -35,7 +35,7 @@ tcp::worker_() { printf "%s\n\n%s" "$(cat response.txt)" "$(cat index.html)" >&$socket_input # main logic done - exec {socket_input}<&- + exec {socket_input}<&- exec {socket_output}<&- }