** 'Butter' instances route HTTP requests through a stack of middleware. mixin Butter {** A const value representing HTTP 1.0staticconst Version http10 := Version("1.0")** A const value representing HTTP 1.1staticconst Version http11 := Version("1.1")** Makes a request and returns the response.abstract ButterResponse sendRequest(ButterRequest req)** Returns an instance of the given middleware type as used by the abstract ButterMiddleware? findMiddleware(Type middlewareType, Bool checked := true)** Returns an read only list of middleware instances used by this 'Butter' abstract ButterMiddleware[] middleware()** Builds a pack of butter from the given middleware stack.** The ordering of the stack *is* important.static Butter churnOut(ButterMiddleware[] middleware := defaultStack){return ButterChain(middleware)}** The default middleware stack. It currently returns new instances of (in order):** - `StickyCookiesMiddleware`** - `StickyHeadersMiddleware`** - `FollowRedriectsMiddleware`** - `ErrOn5xxMiddleware`** - `HttpTerminator`static ButterMiddleware[] defaultStack(){ ButterMiddleware[ StickyCookiesMiddleware(), StickyHeadersMiddleware(), FollowRedirectsMiddleware(), ErrOn5xxMiddleware(), HttpTerminator()]}** Makes a simple HTTP get request to the given URI and returns the response.virtual ButterResponse get(Uri uri){ sendRequest(ButterRequest(uri))}** Make a post request to the URI with the given form data.** The 'Content-Type' is set to 'application/x-www-form-urlencoded'.virtual ButterResponse postForm(Uri uri, Str:Str form){ req := ButterRequest(uri){it.method = "POST"} req.headers.contentType = MimeType("application/x-www-form-urlencoded") req.body.print(Uri.encodeQuery(form))return sendRequest(req)}** Make a post request to the URI with the given String.** The 'Content-Type' is set to 'text/plain'.virtual ButterResponse postStr(Uri uri, Str content, Charset charset := Charset.utf8){ req := ButterRequest(uri){it.method = "POST"} req.headers.contentType = MimeType("text/plain") Buf(){it.charset = charset }.print(content).flip.in.pipe(req.body.out)return sendRequest(req)}** Make a post request to the URI with the given file.** The 'Content-Type' is set from the file extension's MIME type, or 'application/octet-stream' if unknown.virtual ButterResponse postFile(Uri uri, File file){ req := ButterRequest(uri){it.method = "POST"} req.headers.contentType = file.mimeType ?: MimeType("application/octet-stream") file.in.pipe(req.body.out, file.size, true)return sendRequest(req)}override Obj? trap(Str name, Obj?[]? args := null){ middleware.find |mw->Bool| {if(mw.typeof.name.equalsIgnoreCase(name))returntrueif(mw.typeof.name.lower.endsWith("middleware"))if(mw.typeof.name[0..<-"middleware".size].equalsIgnoreCase(name))returntruereturnfalse} ?: throw ButterErr(ErrMsgs.chainMiddlewareNotFound(name), middleware.map {it.typeof.name })}}