123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566moduleServer_core=Cohttp_lwt.Make_server(Io)includeServer_coreopenLwt.Infixletsrc=Logs.Src.create"cohttp.lwt.server"~doc:"Cohttp Lwt server module"moduleLog=(valLogs.src_logsrc:Logs.LOG)letblank_uri=Uri.of_string""letresolve_file~docroot~uri=(* This normalises the Uri and strips out .. characters *)letfrag=Uri.path(Uri.resolve""blank_uriuri)inFilename.concatdocrootfragexceptionIsnt_a_fileletrespond_file?headers~fname()=Lwt.catch(fun()->(* Check this isnt a directory first *)(fname|>Lwt_unix.stat>>=funs->ifUnix.(s.st_kind<>S_REG)thenLwt.failIsnt_a_fileelseLwt.return_unit)>>=fun()->letcount=16384inLwt_io.open_file~buffer:(Lwt_bytes.createcount)~mode:Lwt_io.inputfname>>=funic->Lwt_io.lengthic>>=funlen->letencoding=Cohttp.Transfer.Fixedleninletstream=Lwt_stream.from(fun()->Lwt.catch(fun()->Lwt_io.read~countic>|=function|""->None|buf->Somebuf)(funexn->Log.debug(funm->m"Error resolving file %s (%s)"fname(Printexc.to_stringexn));Lwt.return_none))inLwt.on_success(Lwt_stream.closedstream)(fun()->Lwt.ignore_result@@Lwt.catch(fun()->Lwt_io.closeic)(fune->Log.warn(funf->f"Closing channel failed: %s"(Printexc.to_stringe));Lwt.return_unit));letbody=Cohttp_lwt.Body.of_streamstreaminletmime_type=Magic_mime.lookupfnameinletheaders=Cohttp.Header.add_opt_unless_existsheaders"content-type"mime_typeinletres=Cohttp.Response.make~status:`OK~encoding~headers()inLwt.return(res,body))(function|Unix.Unix_error(Unix.ENOENT,_,_)|Isnt_a_file->respond_not_found()|exn->Lwt.failexn)letcreate?timeout?backlog?stop?on_exn?(ctx=Net.default_ctx)?(mode=`TCP(`Port8080))spec=Conduit_lwt_unix.serve?backlog?timeout?stop?on_exn~ctx:ctx.Net.ctx~mode(callbackspec)