Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-httpclient

Named HTTP clients for Pudu: a client factory, delegating handlers, pooled keep-alive connections, handler lifetimes, logging, and resilience

0.1.1Apache-2.01

InstallClose

Writer.pudu

Pudu51 lines2.1 KB

GitHub ↗
1/** @Transport.Writer.Module — a request written as the bytes that go on the wire */2module PuduLangHttpClient.Transport.Writer34import Std.Bytes as ByteSeq5import Std.Http as Http6import PuduLangHttpClient.Domain.Headers as Headers7import PuduLangHttpClient.Domain.Uri as Uri8import PuduLangHttpClient.Request as Request910/** @Transport.Writer.Form — how the request line names its target */11export type Form = OriginForm | AbsoluteForm1213/// The line break the protocol ends every line with.14const CRLF: Str = "\r\n"1516/// The head and body of a request to an endpoint: the request line in the given form, `host` unless17/// the request names one, the request's headers, the body's headers, the body's length or chunked18/// framing for a streamed body, and any extra headers the route adds.19export fn render(request: &Request.Request, version: &Http.Version, endpoint: &Uri.Endpoint, form: &Form, extra: &Array[(Str, Str)]) -> Bytes {20  let target = match form {21    case OriginForm => Uri.target(request.uri)22    case AbsoluteForm => Uri.withoutFragment(request.uri)23  }24  var head = Http.methodName(&request.method) + " " + target + " " + Http.versionName(version) + CRLF25  if !Headers.has(&request.headers, "host") { head = head + "host: " + Uri.authority(endpoint) + CRLF }26  for pair in request.headers {27    if pair[0].toLower() != "content-length" { head = head + pair[0] + ": " + pair[1] + CRLF }28  }29  let body = match request.content {30    case Some(content) => {31      for pair in content.headers {32        if pair[0].toLower() != "content-length" { head = head + pair[0] + ": " + pair[1] + CRLF }33      }34      content.payload35    }36    case None => ByteSeq.empty()37  }38  let framed = Headers.has(&request.headers, "transfer-encoding")39  let streamed = match request.content {40    case Some(content) => content.stream != None41    case None => false42  }43  if streamed && !framed {44    head = head + "transfer-encoding: chunked" + CRLF45  } else if !framed && (!body.isEmpty() || request.content != None || Http.expectsBody(&request.method)) {46    head = head + "content-length: " + show(body.length()) + CRLF47  }48  for pair in *extra { head = head + pair[0] + ": " + pair[1] + CRLF }49  (head + CRLF).toBytes().concat(body)50}51