Skip to content

Commit e5b9e10

Browse files
WIP
1 parent 1f73d44 commit e5b9e10

1 file changed

Lines changed: 58 additions & 27 deletions

File tree

src/http.c

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
/*
4444
* URL-encodes a string for HTTP requests.
4545
*
46+
* RFC 3986 describes the percent-encoding mechanism:
47+
* https://www.rfc-editor.org/info/rfc3986
48+
*
4649
* The dest buffer size MUST be at least strlen(str) * 3 + 1.
4750
*
4851
* @param[out] dest the buffer to write the URL-encoded string
@@ -172,7 +175,7 @@ static int parse_response_header(const struct phr_header *headers, size_t num_he
172175
uint32_t content_length = 0;
173176
int transfer_encoding_chunked = 0;
174177

175-
for (int i = 0; i != num_headers; ++i) {
178+
for (int i = 0; i != num_headers; i++) {
176179
if (header_name_cmp(headers[i], "Content-Length") == 0) {
177180
long l = strtol(headers[i].name, NULL, 10);
178181

@@ -218,14 +221,21 @@ int http_receive(
218221
uint32_t header_size = 0;
219222
uint32_t content_size = 0;
220223
int chunked = 0;
224+
struct phr_chunked_decoder decoder = {0}; // zero-clear
221225

222226
buffer = malloc(capacity + 1); // room for terminal '\0'
223227
if (buffer == NULL)
224228
return ERR_HTTP_NO_MEM;
225229

226230
while (1) {
227231
int n;
232+
int minor_version, status;
233+
const char *msg;
234+
size_t msg_len;
235+
struct phr_header headers[100]; // FIXME
236+
size_t num_headers = ARRAY_SIZE(headers);
228237

238+
/* read SSL stream into buffer as long as ERR_SSL_AGAIN */
229239
while ((n = safe_ssl_read(tunnel->ssl_handle,
230240
(uint8_t *) buffer + bytes_read,
231241
capacity - bytes_read)) == ERR_SSL_AGAIN)
@@ -241,23 +251,22 @@ int http_receive(
241251

242252
log_debug_details("%s:\n%s\n", __func__, buffer);
243253

244-
if (!header_size) {
245-
/* Have we reached the end of the HTTP header? */
246-
int minor_version, status;
247-
const char *msg;
248-
size_t msg_len;
249-
struct phr_header headers[100]; // FIXME
250-
size_t num_headers = ARRAY_SIZE(headers);
251-
254+
if (content_size == 0 && !chunked) {
255+
/* parse the HTTP response header */
252256
n = phr_parse_response(buffer, bytes_read,
253-
&minor_version, &status,
254-
&msg, &msg_len,
255-
headers, &num_headers,
256-
last_bytes_read);
257+
&minor_version, &status,
258+
&msg, &msg_len,
259+
headers, &num_headers,
260+
last_bytes_read);
257261
if (n > 0) {
258262
header_size = n;
263+
log_error("*** header_size: %u\n", header_size);
259264
n = parse_response_header(headers, num_headers,
260265
&content_size, &chunked);
266+
if (content_size)
267+
log_error("*** content_size: %u\n", content_size);
268+
if (chunked)
269+
log_error("*** chunked: %d\n", chunked);
261270
if (n < 0) {
262271
free(buffer);
263272
return n;
@@ -272,24 +281,46 @@ int http_receive(
272281
} else if (n == -2) {
273282
/* response is partial, continue the loop */
274283
} else {
275-
/* failed to parse the response */
284+
/* failed to parse the response header */
276285
assert(n == -1);
286+
free(buffer);
287+
return ERR_HTTP_INVALID;
277288
}
278289
}
279-
280-
if (header_size) {
281-
/* Have we reached the end of the HTTP body? */
282-
if (chunked) {
283-
static const char EOB[7] = "\r\n0\r\n\r\n";
284-
285-
/* Last chunk terminator. Done naively. */
286-
if (bytes_read >= sizeof(EOB) &&
287-
!memcmp(&buffer[bytes_read - sizeof(EOB)],
288-
EOB, sizeof(EOB)))
289-
break;
290+
if (chunked) {
291+
size_t bufsz = bytes_read - header_size;
292+
293+
n = phr_decode_chunked(&decoder,
294+
&buffer[header_size], &bufsz);
295+
296+
if (n >= 0) {
297+
/* body is complete */
298+
if (n > 0) {
299+
/* garbage after body */
300+
log_warn("Garbage after body (%d bytes).\n",
301+
n);
302+
}
303+
} else if (n == -2) {
304+
/* body is incomplete, continue the loop */
290305
} else {
291-
if (bytes_read >= header_size + content_size)
292-
break;
306+
/* failed to parse the chunked body */
307+
assert(n == -1);
308+
free(buffer);
309+
return ERR_HTTP_INVALID;
310+
}
311+
//~ /* parse the HTTP response chunked body */
312+
//~ static const char EOB[7] = "\r\n0\r\n\r\n";
313+
314+
//~ /* Last chunk terminator. Done naively. */
315+
//~ if (bytes_read >= sizeof(EOB) &&
316+
//~ !memcmp(&buffer[bytes_read - sizeof(EOB)],
317+
//~ EOB, sizeof(EOB)))
318+
//~ break;
319+
} else if (content_size > 0) {
320+
/* read until the end of the HTTP response body */
321+
if (bytes_read >= header_size + content_size) {
322+
buffer[bytes_read] = '\0';
323+
break;
293324
}
294325
}
295326

0 commit comments

Comments
 (0)