Skip to content

Commit

Permalink
better response handling, ability to send raw body
Browse files Browse the repository at this point in the history
  • Loading branch information
massivefermion committed Nov 24, 2023
1 parent 0826f5c commit cda8015
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 34 deletions.
2 changes: 1 addition & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name = "dove"
version = "0.10.2"
version = "0.11.0"

description = "HTTP client written in and for Gleam"
gleam = ">= 0.32.0"
Expand Down
57 changes: 45 additions & 12 deletions src/dove.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@ pub type RequestOption(a) {

pub type RequestBody {
JSON(String)
Binary(BitArray)
EmptyRequestBody
PlainText(String)
}

pub type ResponseBody(a) {
Raw(String)
Raw(BitArray)
String(String)
JSONDecoded(a)
EmptyResponseBody
InvalidOrUnexpectedJSON(String, json.DecodeError)
InvalidOrUnexpectedJSON(BitArray, json.DecodeError)
}

pub opaque type Connection(a) {
Expand Down Expand Up @@ -92,11 +94,13 @@ pub fn request(

let #(body, headers) = case request.body {
JSON(body) -> #(
option.Some(body),
body
|> bit_array.from_string
|> option.Some,
list.append(
request.headers,
[
#("content-type", "application/json"),
#("content-type", "application/json; charset=utf-8"),
#(
"content-length",
body
Expand All @@ -108,11 +112,13 @@ pub fn request(
)

PlainText(body) -> #(
option.Some(body),
body
|> bit_array.from_string
|> option.Some,
list.append(
request.headers,
[
#("content-type", "text/plain"),
#("content-type", "text/plain; charset=utf-8"),
#(
"content-length",
body
Expand All @@ -123,6 +129,22 @@ pub fn request(
),
)

Binary(body) -> #(
option.Some(body),
list.append(
request.headers,
[
#("content-type", "application/octet-stream"),
#(
"content-length",
body
|> bit_array.byte_size
|> int.to_string,
),
],
),
)

EmptyRequestBody -> #(option.None, request.headers)
}

Expand Down Expand Up @@ -230,7 +252,7 @@ fn receive_internal(conn: Connection(a), selector, timeout) {
#(status, headers, option.Some(body)) ->
case decoder {
option.Some(decoder) ->
case json.decode(body, decoder) {
case json.decode_bits(body, decoder) {
Ok(value) ->
Ok(gleam_http_response.Response(
status,
Expand All @@ -244,12 +266,23 @@ fn receive_internal(conn: Connection(a), selector, timeout) {
InvalidOrUnexpectedJSON(body, decode_error),
))
}

option.None ->
Ok(gleam_http_response.Response(
status,
headers,
Raw(body),
))
case bit_array.to_string(body) {
Ok(body) ->
Ok(gleam_http_response.Response(
status,
headers,
String(body),
))

Error(Nil) ->
Ok(gleam_http_response.Response(
status,
headers,
Raw(body),
))
}
}

#(status, headers, option.None) ->
Expand Down
3 changes: 1 addition & 2 deletions src/dove/error.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import mug

pub type Error {
MoreNeeded
IsNotString
InvalidHeader
InvalidHeaders
WrongPacketType
InvalidStatusLine
TCPError(mug.Error)
Expand Down
13 changes: 6 additions & 7 deletions src/dove/request.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub fn encode(
path: String,
query: option.Option(String),
headers: List(#(String, String)),
body: option.Option(String),
body: option.Option(BitArray),
) {
use <- bail_if_invalid_header(headers)
let headers = list.prepend(headers, #("host", host))
Expand All @@ -24,14 +24,13 @@ pub fn encode(
request_line(method, path) <> {
list.map(headers, encode_header)
|> string.join("")
} <> "\r\n" <> {
case body {
option.Some(body) -> body
option.None -> ""
}
}
} <> "\r\n"
}
|> bit_array.from_string
|> bit_array.append(case body {
option.Some(body) -> body
option.None -> <<>>
})
|> Ok
}

Expand Down
20 changes: 8 additions & 12 deletions src/dove/response.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub fn decode(response: BitArray) {
<<>>,
True,
))

use status_line <- result.then(
bit_array.to_string(status_line)
|> result.replace_error(error.InvalidStatusLine),
Expand All @@ -20,7 +21,7 @@ pub fn decode(response: BitArray) {
use #(headers, rest) <- result.then(consume_till_double_crlf(rest, <<>>))
use headers <- result.then(
bit_array.to_string(headers)
|> result.replace_error(error.InvalidHeader),
|> result.replace_error(error.InvalidHeaders),
)

case decode_status_line(status_line) {
Expand Down Expand Up @@ -70,14 +71,9 @@ pub fn decode(response: BitArray) {
Ok(#(#(status, headers, option.Some(decompressed)), rest))
}

_ -> {
use body <- result.then(
bit_array.to_string(body)
|> result.replace_error(error.IsNotString),
)
Ok(#(#(status, headers, option.Some(body)), rest))
}
_ -> Ok(#(#(status, headers, option.Some(body)), rest))
}

option.None -> Ok(#(#(status, headers, option.None), rest))
}
}
Expand All @@ -88,10 +84,10 @@ pub fn decode(response: BitArray) {
}
}

fn decode_headers(binary: String, storage: List(http.Header)) {
pub fn decode_headers(binary: String, storage: List(http.Header)) {
use result <- result.then(
decode_header(binary)
|> result.replace_error(error.InvalidHeader),
|> result.replace_error(error.InvalidHeaders),
)

case result {
Expand Down Expand Up @@ -203,7 +199,7 @@ fn decode_status_line(binary: String) -> Result(DecodeResult, Nil)
fn decode_header(binary: String) -> Result(DecodeResult, Nil)

@external(erlang, "dove_ffi", "gunzip")
fn gunzip(compressed: BitArray) -> Result(String, String)
fn gunzip(compressed: BitArray) -> Result(BitArray, String)

@external(erlang, "dove_ffi", "inflate")
fn inflate(compressed: BitArray) -> Result(String, String)
fn inflate(compressed: BitArray) -> Result(BitArray, String)

0 comments on commit cda8015

Please sign in to comment.