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