Skip to content

Commit d35a40a

Browse files
committed
Model Body and Buf
1 parent f320bb3 commit d35a40a

File tree

2 files changed

+91
-15
lines changed

2 files changed

+91
-15
lines changed

hyper-capi/examples/client.c

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ int main(int argc, char *argv[]) {
167167
if (!hyper_request_set_method(req, (uint8_t *)"POST", 4)) {
168168
return 1;
169169
}
170-
if (!hyper_request_set_uri(req, (uint8_t *)"http://httpbin.org", sizeof("http://httpbin.org") - 1)) {
170+
if (!hyper_request_set_uri(req, (uint8_t *)"/", sizeof("/") - 1)) {
171171
return 1;
172172
}
173173

@@ -176,8 +176,11 @@ int main(int argc, char *argv[]) {
176176

177177
hyper_executor_push(exec, task);
178178

179-
hyper_response *resp;
179+
// The body will be filled in after we get a response, and we will poll it
180+
// multiple times, so it's declared out here.
181+
hyper_body *resp_body = NULL;
180182

183+
// The polling state machine!
181184
while (1) {
182185
hyper_executor_poll(exec);
183186
while (1) {
@@ -187,30 +190,53 @@ int main(int argc, char *argv[]) {
187190
}
188191
switch (hyper_task_type(task)) {
189192
case HYPER_TASK_CLIENT_SEND:
193+
;
190194
// Take the results
191-
resp = hyper_task_value(task);
192-
// fall through
195+
hyper_response *resp = hyper_task_value(task);
196+
hyper_task_free(task);
197+
198+
uint16_t http_status = hyper_response_status(resp);
199+
200+
printf("HTTP Status: %d", http_status);
201+
202+
hyper_headers *headers = hyper_response_headers(resp);
203+
hyper_headers_iter(headers, print_each_header, NULL);
204+
205+
resp_body = hyper_response_body(resp);
206+
hyper_executor_push(exec, hyper_body_next(resp_body));
207+
208+
break;
209+
case HYPER_TASK_BODY_NEXT:
210+
;
211+
// A body chunk is available
212+
hyper_buf *chunk = hyper_task_value(task);
213+
hyper_task_free(task);
214+
215+
if (!chunk) {
216+
// body is complete!
217+
printf("\n\nDone!");
218+
return 0;
219+
}
220+
221+
// Write the chunk to stdout
222+
hyper_str s = hyper_buf_str(chunk);
223+
write(1, s.buf, s.len);
224+
hyper_buf_free(chunk);
225+
226+
// Queue up another body poll.
227+
hyper_executor_push(exec, hyper_body_next(resp_body));
228+
break;
193229
default:
194230
hyper_task_free(task);
195231
break;
196232
}
197233
}
198234

199-
// If the response is ready, break out for now...
200-
if (resp != NULL) {
201-
break;
202-
}
203-
235+
// All futures are pending on IO work, so select on the fds.
204236
select(1, &all_fds->read, &all_fds->write, &all_fds->excep, NULL);
205237

206238
}
207239

208-
uint16_t http_status = hyper_response_status(resp);
209-
210-
printf("HTTP Status: %d", http_status);
211-
212-
hyper_headers *headers = hyper_response_headers(resp);
213-
hyper_headers_iter(headers, print_each_header, NULL);
214240

215241
return 0;
216242
}

hyper-capi/include/hyper.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,19 @@ typedef struct hyper_response hyper_response;
2222

2323
typedef struct hyper_headers hyper_headers;
2424

25+
typedef struct hyper_body hyper_body;
26+
27+
typedef struct hyper_buf hyper_buf;
28+
2529
typedef struct hyper_task hyper_task;
2630

2731
typedef struct hyper_waker hyper_waker;
2832

2933
typedef struct hyper_executor hyper_executor;
3034

35+
// A string reference.
36+
//
37+
// The data in here typically is not owned by this struct.
3138
typedef struct hyper_str {
3239
const uint8_t *buf;
3340
size_t len;
@@ -43,6 +50,11 @@ typedef enum {
4350
HYPER_IT_BREAK,
4451
} hyper_iter_step;
4552

53+
typedef enum {
54+
HYPER_POLL_READY,
55+
HYPER_POLL_PENDING,
56+
} hyper_poll;
57+
4658
// HTTP ClientConn
4759

4860
// Starts an HTTP client connection handshake using the provided IO transport
@@ -141,6 +153,11 @@ uint16_t hyper_response_status(hyper_response *response);
141153
// `hyper_response` has been freed.
142154
hyper_headers *hyper_response_headers(hyper_response *response);
143155

156+
// Take ownership of the body of this response.
157+
//
158+
// It is safe to free the response even after taking ownership of its body.
159+
hyper_body *hyper_response_body(hyper_response *response);
160+
144161
// HTTP Headers
145162

146163
// Sets the header with the provided name to the provided value.
@@ -166,6 +183,38 @@ void hyper_headers_iter(hyper_headers *headers,
166183
hyper_str value),
167184
void *userdata);
168185

186+
// HTTP Body
187+
188+
// Sets the `userdata` that is passed to the `poll` callback.
189+
void hyper_body_set_data(hyper_body *body, void *userdata);
190+
191+
// Set the poll function for this body.
192+
//
193+
// This function will be called each time more data is desired to write to
194+
// the transport. Use `hyper_body_set_data` to set the `userdata` argument.
195+
void hyper_body_set_poll(hyper_body *body,
196+
hyper_poll (*func)(void *userdata,
197+
hyper_waker *waker));
198+
199+
// Return a task that will yield the next chunk of bytes of the body, when
200+
// available.
201+
//
202+
// This task has a return type tag of `HYPER_TASK_BODY_NEXT`, which will
203+
// give a value of `hyper_buf *`.
204+
//
205+
// When the body is complete, the task's value will be `NULL`.
206+
hyper_task *hyper_body_next(hyper_body *body);
207+
208+
// TODO: hyper_body_trailers()
209+
210+
// Free this buffer.
211+
void hyper_buf_free(hyper_buf *buf);
212+
213+
// Get a reference to the bytes of this buf.
214+
//
215+
// The returned `hyper_str` is not safe to use after freeing the `hyper_buf *`.
216+
hyper_str hyper_buf_str(hyper_buf *buf);
217+
169218
// Futures and Executors
170219

171220
hyper_executor *hyper_executor_new();
@@ -189,6 +238,7 @@ typedef enum {
189238
HYPER_TASK_BG,
190239
HYPER_TASK_CLIENTCONN_HANDSHAKE,
191240
HYPER_TASK_CLIENT_SEND,
241+
HYPER_TASK_BODY_NEXT,
192242
} hyper_task_return_type;
193243

194244
// Query the return type of this task.

0 commit comments

Comments
 (0)